So I have a use case in which I enter indexes and descriptions which belong to a round. I created a JS function that allows me to enter these indexes and descriptions. When I strip the data from the post request I get the following data:
['0,This is a testround', '1,This is a new testround']
I want to split this data so that I can seperate the 0 in an index variable and the following description "This is a testround" in a description variable. Please note that the description can only contain comma's. The indexes are not always corresponding with the indexes of an array: [[0,"Description1"],[5,"Description2"]] could happen
A possible solution could be to split the string on a comma and use str[0] for the index and the other parts for the description but to me this would look like an ugly solution.
What should I do?
I use the following JS to save the rounds to a playerdata div from which i extract the list above (in which items is the list with the index and description)
function item_checkbox(items,n) {
return `
<input type="checkbox" style="display:none;" name="${itemList[n]}" value="${items}" checked>
`
}
function add_to_itemData(items, n) {
itemDataEl = document.getElementById(itemData[n])
itemDataEl.innerHTML = itemDataEl.innerHTML + item_checkbox(items, n)
}
Thanks for any help in advance
While you say that it would be an "ugly" solution to solve it by splitting, I think it's a pretty straightforward routine, given the format the data is returned to you.
['0,This is a testround', '1,This is a new testround'].map(v => v.split(','));
... would translate correctly to:
[
[ "0", "This is a testround" ],
[ "1", "This is a new testround" ]
]
But I guess I get what you mean. There are a few possible problems - for example, that of key uniqueness. You could solve this one by keeping each row into Javascript objects instead of arrays, and you can convert it quite easily by using Object.fromEntries(), since it conveniently accepts each row of bidimensional arrays as key/value pairs:
Object.fromEntries([
[ "0", "This is a testround" ],
[ "1", "This is a new testround" ],
[ "1", "This is a dupe testround" ] // this will overwrite the previous entry
]);
// {0: "This is a testround", 1: "This is a dupe testround"}
You might want to take a few extra steps for additional control, like using .trim() to remove leading or trailing whitespaces or testing/filtering/splitting them using a custom regex.
Related
I am working on a project that has JSON format output. I need a clarity on the JSON array structure. So There are fields that are multiple entry like an array. If an element is an array but has only one value, does it still include an array node '[' in the structure?
Example:
This is a sample JSON element which is an array and has multiple values.
"Talents": [
{
"Items": "test"
},
{
"Items": "test"
}
]
If this element does not have multiple values, will it appear as below?
"Talents":
{
"Items": "test"
}
The '[' does not appear for an array type element with single value. Can someone Pls clarify this?
Single-item arrays will still include the array brackets in JSON format, as they are still arrays. In other words, there is no such native mechanism which converts single-item arrays to a non-array representation. So with your single-item example, it would be represented like this:
"Talents": [
{
"Items": "test"
}
]
You can easily test this out with some simple code:
let jsonSingleItem = { "Talents": [ {"Items": "item1"} ] };
let arraySingleItem = [ {"Items": "item1"} ];
console.log(JSON.stringify(jsonSingleItem));
console.log(jsonSingleItem);
console.log(arraySingleItem);
Which yields the following output:
{"Talents":[{"Items":"item1"}]}
{ Talents: [ { Items: 'item1' } ] }
[ { Items: 'item1' } ]
So in all cases (a stringified JSON object, native JSON, and a javascript array) the single item is still in an array.
Note: It is not uncommon that a consumer of an API will send data (i.e. JSON) in ways which are outside the agreed-upon contract/schema that API defines, and this (sending an object instead of a single-object array when there is just one item) is one example I have seen before. It would be up to the owner/developer of the API as to whether they build in flexibility to handle input which deviates from the API schema.
Square brackets ("[]") denotes JSONArray which in your case can access like
Talents[0]
will return
{
"Items": "test"
}
In second case, curve brackets denotes an JSON object. If you want to access value of items. Than you can by
Talents.Items
OR
Talents["Items"]
will return
"Test"
for complete reference,
JSON Syntax
Below sample shows some name and value pair of a json file. In real life I have over 300 name and value pair for the json file where each name is different. SO I thought of getting the names in one array using regex and values in another.
I've reviewed many other questions like this but can't make a head or tail out of them.
what I need is:
I need 2 regular expressions for this piece of JSON.
I want to capture the names with one regex and values with another regex.
The names should include: roleId status seq item1 item2 ... ghost and values should include: 43322 841-1 ... null. NOTICE I left out comma intentionally because I don't want it. Also notice that the last value has no comma.
BTW, I'm using jsonslurper in soapui to parser this json.
I don't if there's any other way I can do it besides regex. Anything will be ok as long as I don't have to type each name to get the value like productDetails[0].roleId which returns 43322. I will have to write over 300 of them.
{
"productDetails": [{
"roleId": 43322,
"status": "",
"seq": "841-1",
"item1": "Yellow",
"item2": "green",
"majorColor": "Black",
"srs": "abc",
"additionalBrightness": null,
"isThisNull": null,
"burned": null,
"ghost": null
}]}
Thanks,
I am writing a program that checks whether particular keywords come back in a string, using .includes(). I have categorised the keywords in a json object, mostly because I want separate counts per category.
My first approach was to loop through each word in the text, and run an if-statement for each array in the keywords object. This resulted in 6 different if-statements for each word in the text, which I figured might not be very efficient, especially because many words in the text do not match any of the words in any of the keywords arrays.
I then decided to check whether it would be better to flatten my keywords object to a single array, and to check whether a word matched any of the words in the flattened array before moving on to the more specific arrays of keywords.
I have included a simplified example below:
The list of keywords:
{
"category1": {
"subcategory1": [
"keyword",
"keyword"
],
"subcategory2": [
"keyword"
]
},
"category2" : {
"subcategory1" : [
"keyword",
"keyword",
"keyword"
],
"subcategory2" : [
"keyword",
"keyword"
]
},
"category3": [
"keyword",
"keyword",
"keyword"
]
}
Now, for the second approach, I flattened the json object (keywordList) to a number of arrays, then reducing it to a single array (keywordListArray) using reduce(). I then included an if-statement that would filter out any of the words that were in neither of the arrays, before executing more specific tests.
for (let property in text) {
if (keywordListArray.includes(property)) {
// Will this improve performance?
if (keywordList.category.subcategory.includes(property)) {
result.category.subcategory ++;
}
if (keywordList.category.otherSubcategory.includes(property)) {
result.category.subcategory ++;
}
}
}
I then checked the execution time of each approach. I have provided a simplified example, but in my case, my keywords object consisted of 6 different array with about 10 keywords each. The input text is about 200 characters long, and will probably return some 15 matches with the keywords.
text of 200 words:
Execution time without flattened array and prior filter (approach 1): 10-12 ms
Execution time with flattened array and prior filter (approach 2): 9-11 ms
I have also tested with 400 words, but there is barely any difference in execution time.
I was wondering which approach you guys would recommend, both in terms of writing 'good code' and in terms of performance?
Two assumptions to get started:
The more words of the text that match a keyword, the more redundant the prior filter using the flattened array.
The more categories (arrays) in the json object, the more if statements, and the slower the approach without prior filter.
Is this true, and do you guys expect there to be a large performance difference when employing this in a larger scale project?
Thanks in advance!
Daan
I would take a single object for counting the keywords with kewords as key and an object for count, categories and sub categories.
{
pizza: {
count: 0,
category: 'Food',
subcategory: 'Italian'
},
ramen: {
// ...
}
}
Later, you could render an object with all keywords grouped by category and subcategory.
The advantage of the above, you could check just if the key is in the object and take then the key for increment of the counter, like
if (property in object) {
object.count++;
}
This may be a very simple question but I really can't seem to make it work.
I have several JSON lines and a notes array.
Using notes.push(JSONline) I am saving one JSON line per array position, I assume, so in the following manner:
//notes[1]
{"id":"26","valuee":"20","datee":"2016-04-05T15:15:45.184+0100","id2":51}
//notes[2]
{"id":"27","valuee":"134","datee":"2016-04-05T15:15:47.238+0100","id2":53}
//notes[3]
{"id":"26","valuee":"20","datee":"2016-04-05T15:15:45.184+0100","id2":52}
Here is my problem: I want to print one specific attribute, for example id from one specific JSON line in the array. How can I do this?
When I do console.log(notes) it prints all the JSON lines just as expected. But if I do console.log(notes[1]) it prints the first character of the JSON line in that position, not the whole line.
Similarly console.log(notes[1].id) does not print the id from the first JSON line, in fact it prints 'undefined'.
What am I doing wrong?
Thank you so much.
I'd recommend that you parse all the json when you are pushing to notes, like:
notes.push(JSON.parse(JSONLine))
If you are somehow attached to having json strings in an array instead of objects, which I wouldn't recommend, you could always just parse once you have the jsonLine id
JSON.parse(notes[id]).id
Basically, you want to use JSON.parse for either solution and I'd strongly recommend converting them to objects once at the beginning.
You need to remember that JSON is the string representation of a JS object. JS strings have similar index accessor methods to arrays which is why you can write console.log(notes[0]) and get back the first letter.
JavaScript doesn't allow you to access the string using object notation, however, so console.log(notes[0].id) will not work and the reason you get undefined.
To access the data in the string using this method you need to parse the string to an object first.
var notes = ['{"id":"26","valuee":"20","datee":"2016-04-05T15:15:45.184+0100","id2":51}'];
var note0 = JSON.parse(notes[0]);
var id = note0.id;
DEMO
This leaves the question of why you have an array of JSON strings. While it's not weird or unusual, it might not be the most optimum solution. Instead you could build an array of objects and then stringify the whole data structure to keep it manageable.
var obj0 = {
"id": "26",
"valuee": "20",
"datee": "2016-04-05T15:15:45.184+0100",
id2: 51
};
var obj1 = {
"id": "27",
"valuee": "134",
"datee": "2016-04-05T15:15:47.238+0100",
"id2": 53
}
var arr = [obj0, obj1];
var json = JSON.stringify(arr);
OUTPUT
[
{
"id": "26",
"valuee": "20",
"datee": "2016-04-05T15:15:45.184+0100",
"id2": 51
},
{
"id": "27",
"valuee": "134",
"datee": "2016-04-05T15:15:47.238+0100",
"id2": 53
}
]
You can then parse the JSON back to an array and access it like before:
var notes = JSON.parse(json);
notes[0].id // 26
That's because you have {"id": "value"... as a string in your key value pairs. "id" is a string so you can't reference it like a property. 1. use
var notes = JSON.parse(notes);
as mentioned in the comments by The alpha
or remove the quotes try
{id:"26", ...}
that's why notes[i].id is returning undefined
I'm trying to generate a tree structure in JavaScript from a flat array. This would usually be a fairly straightforward proposition - simply retain a 'stack' array with references to ancestor objects of the current working scope ordered by nesting depth - push a new element onto the stack when entering another nested level, and pop it off when leaving one, replacing the current working element with the object referenced by the (new) last array item.
Unfortunately this requires the capability to pass-by-reference, which JavaScript doesn't have (well, doesn't have in any meaningful way that I know how I could use for this problem.)
To give a bit of background, I'm trying to turn an arbitrarily long/complicated string containing nested XML-style (but not XML, so an XML parser can't be used instead) tokens into a structure similar to the one below:
Expected Input:
[
"<token>",
"<my non compliant token>",
"some text at this level",
"<some other token>",
"some more text",
"<yet another token>",
"more text",
"</yet another token>",
"blah!",
"</some other token>",
"</token>",
"more text"
]
Expected Output
[
{
"token": "<token>",
"children": [
{
"token": "<my non compliant token>",
"children": [
"some text at this level",
{
"token": "<some other token>",
"children": [
"some more text",
{
"token": "<yet another token>",
"children": [ "more text" ]
},
"blah!"
]
}
]
}
]
},
"more text"
]
To clarify - I'm not after an entire algorithm (but I'd be interested if you want to provide your implementation) - just a good method for maintaining current position in the outputted tree (or an entirely different/better way of generating tree objects!) Don't get too caught up on how the tokens work - they're not XML and for the purpose of the exercise could be formatted entirely differently.
Any input would be greatly appreciated!
Your strings look easy to parse. I think I would do something like this:
var stack = [];
var array = [];
for (var i in strings) {
var s = strings[i];
if (s.indexOf("</") == 0) {
array = stack.pop();
} else if (s.indexOf("<") == 0) {
var obj = {token: s, children: []};
array.push(obj);
stack.push(array);
array = obj.children;
} else {
array.push(s);
}
}
Idea #1
Here's an answer you probably weren't anticipating.
Looking at your expect output, I was wondering if it's easiest to just generate JSON and then eval it when you're done. No references at all.
When going through your flat array, you basically have three operations:
You add more data to the current object
You close off the current object
You create a new child object
You can do all three of those fairly easily by just appending the appropriate text onto a JSON string you're building as you iterate through your source array to literally just generate the text you show in your expected output. When done, run that JSON string through eval. You may need a few safety checks to verify that each array and object is closed properly if there are errors in the input, but it should work fine.
Idea #2
You can still use your stack array. I'm not sure exactly why you need to pass by reference, but you can just pass an index into the array around and have everyone modify the master copy of the array that way via index. Using local functions, the master array can be a common data value that is local to your main function, but essentially global to all your sub-functions so they can all shared access to it.
This would look something like this:
function ParseRawData(rawData)
{
var parentScopeArray = []; // main parent scope of objects
function processTag(x)
{
// you can access parentScopeArray directly here and
// and be accessing it by reference
}
// other code or local functions here
}
Idea #3
If you want to pass the array into a function and have the master copy modified (perhaps the reason you're thinking of pass by reference), the javascript design pattern is to pass the array in and return a modified array, replacing the entire original array with the modified one that is returned.