Proper way to iterate over two dimensional json - javascript

I have a two dimensional json that looks like:
[[{"ID":1,"Name":"....","Ct":123, "Time":"2018-05-07T00:00:00"},
{"ID":2,"Name":"....","Ct":123, "Time":"2018-05-07T00:01:00"}],
[{"ID":3,"Name":"....","Ct":123, "Time":"2018-05-07T00:02:00"},
{"ID":4,"Name":"....","Ct":123, "Time":"2018-05-07T00:03:00"}]]
It is serialized from C# object. Anyway I try to iterate over this json like:
for (var key in data) // first loop
{
var item = data[key];
for (var key2 in item) // second loop
{
// some code...
}
}
Where the first loop should iterate two times: during first iteration the second loop should iterate over two objects with IDs 1 and 2; and during second iteration over objects with IDs 3 and 4.
I guess the problem is that first loop doesn't have Key because first loop iterates only one time and second loop iterates over objects with IDs 1,2,3,4.
How can I iterate over this as two dimensional tab then?
[EDIT]
I made a mistake during iterating inside second loop and it looked like it doesn't iterate. The solution above is correct.

For loop should work but you can also use maps/forEach/for-of to iterate over arrays:
var input = [
[{"ID":1,"Name":"....","Ct":123, "Time":"2018-05-07T00:00:00"},
{"ID":2,"Name":"....","Ct":123, "Time":"2018-05-07T00:01:00"}],
[{"ID":3,"Name":"....","Ct":123, "Time":"2018-05-07T00:02:00"},
{"ID":4,"Name":"....","Ct":123, "Time":"2018-05-07T00:03:00"}]
];
input.map(outElem => {
console.log('======== outter ========');
outElem.map(inElem => {
console.log('======== inner ========');
console.log(inElem.ID);
});
});
// Output:
======== outter ========
======== inner ========
1
======== inner ========
2
======== outter ========
======== inner ========
3
======== inner ========
4
Or forEach:
input.forEach(outElem => {
console.log('======== outter ========');
outElem.forEach(inElem => {
console.log('======== inner ========');
console.log(inElem.ID);
});
});
Or for of:
for (const outElem of input) {
console.log('======== outter ========');
for (const inElem of outElem) {
console.log('======== inner ========');
console.log(inElem.ID);
}
}

var data = [
[{
"ID": 1,
"Name": "....",
"Ct": 123,
"Time": "2018-05-07T00:00:00"
},
{
"ID": 2,
"Name": "....",
"Ct": 123,
"Time": "2018-05-07T00:01:00"
}
],
[{
"ID": 3,
"Name": "....",
"Ct": 123,
"Time": "2018-05-07T00:02:00"
},
{
"ID": 4,
"Name": "....",
"Ct": 123,
"Time": "2018-05-07T00:03:00"
}
]
];
for (var key in data) // first loop
{
var item = data[key];
console.log('======== outter ========');
for (var key2 in item) // second loop
{
console.log('======== inner ========');
console.log(item[key2].ID);
}
}

Related

How do I loop through a JavaScript object?

I'm trying to loop through this object and modify some values however I'm getting just the key when I log it.
this.restProviderService.getMessages(this.gameService.getStepId(), this.gameService.teamId).subscribe(messages => {
console.log(messages);
for (var m in messages) {
console.log(m);
}
});
console.log(messages)
[
{
"id": "3",
"chatId": "1_1",
"user_id": "21",
"userName": "batman",
"msg": "banananananana",
"createdAt": "1632507755"
},
{
"id": "2",
"chatId": "1_1",
"user_id": "31",
"userName": "jennyg",
"msg": "asdfasdfasdf",
"createdAt": "1632507721"
}
]
Console.log(m)
0
1
A for in loop in JS gives you the key. What you do is
for (var m in messages) {
var message = messages[m];
console.log(message);
}
or
for (var m of messages) {
console.log(m);
}
You are looking for a for...of loop.
In Javascript, a for...in loop will return the index each iteration. (0, 1, so on)
A for...of loop will return the item at each sequential index.
for (var m of messages) {
console.log(m);
//Will log each item in the array in order
}
You could also use the array method forEach:
messages.forEach((m, index) => {
console.log(m); // Will print each object
console.log(index); // 0, 1, 2
});
Relevant MDN
You may also be having trouble because you are dealing with an "array-like object", which can be returned from some methods. Here are some ways to convert it to a usual array. But, TLDR:
let typicalArray = [...messages];
//Do stuff with typicalArray

If div children don't have same text content then do action

I'm trying to create DOM elements for an Ingredient filter bar, based on JSON file objects.
The problem is that the same ingredient can appear in several objects, and in that case it should only create the dom element once, not for each time the ingredient occures.
I've tried with childNode, value, innerHTML and !=== but can't figure out the solution. It either creates no element at all, or all of them with duplicates.
Any ideas?
Here is a codePen to help : https://codepen.io/enukeron/pen/eYdgyzx
I also tried with an array to keep track of seen values at this codepen :
https://codepen.io/enukeron/pen/ExgZoLa
JS:
const ingredientDropdown = document.getElementById('ingredientDropdown');
for(var j = 0; j < IngredientList.length; j++) {
if (ingredientDropdown.children.textContent !== IngredientList[j].ingredient) {
var ingredientSearchItems = document.createElement("p");
ingredientSearchItems.textContent = IngredientList[j].ingredient;
ingredientDropdown.appendChild(ingredientSearchItems);
}
}
The JSON file has this format :
{
"id": 49,
"name": "Tropical smoothie",
"servings": 4,
"ingredients": [
{
"ingredient": "Bananas",
"quantity": 2
},
{
"ingredient": "Kiwis",
"quantity": 3
},
{
"ingredient": "Mango",
"quantity": 1
},
{
"ingredient": "Pineapple",
"quantity": 4,
"unit":"slices"
},
{
"ingredient": "Honey",
"quantity": 2,
"unit": "tablespoons"
}
],
"time": 0,
"description":"Chop the fruit. Liquefy in the blender. Chill. Serve",
"appliance": "Blender",
"ustensils":["couteau", "verres"]
}, etc.....
The actual result is :
The Expected Result is :
You could create a function like the following:
function filterIngredients(recipes){
let return_arr = [];
recipes.forEach((recipe, index, array)=>{
let ingredients = recipe["ingredients"];
ingredients.forEach((ingredient, index, inner_array)=>{
if(!return_arr.includes(ingredient["ingredient"])){
return_arr.push(ingredient["ingredient"]);
}
});
});
return return_arr;
}
And then call the function as follows:
var ingredients = filterIngredients(recipes);
You can then loop through ingredients and display them in the div as you want (hoping this is what you wanted in the first place).
Here is a link to my pen where I implemented it:
https://codepen.io/AnirudhMS/pen/MWjJQgg?editors=1010

How to get nth level of parsed json?

I have a JSON that has three levels and it's stored as Array I need to get 2nd level(count started from 0) and below in each level has 10+ elements. How it can be implemented on JavaScript.Need your help. All response will be helpful.
ps. some 1st level and 2nd level elements can be empty
[
{
"name": "0th level first", //0th level
"options": [
{
"name": "1st level Cafe", // 1st level
"options": [
{
"name": "2nd level Staff", //2nd level
"options": [
{
"name": "Gary", //3rd level
"age": 18
},
{
"name": "James", //3rd level
"age": 25
}
]
}
]
}
]
}
]
Probably this one? :)
data.forEach((value, index) => {
for(stage0 in value){
if(typeof value[stage0] === 'object'){
value[stage0].forEach((val, index) => {
for(stage1 in val){
if(typeof val[stage1] === 'object'){
val[stage1].forEach((val2, index) => {
for(stage2 in val2){
console.log(val2[stage2]);
}
})
}
}
})
}
}
})
You can use array.forEach which will be only iterating through each level.
on first loop there is a property call options which is an array, you need to loop through the options array in 0 level, on the second loop again one more options array comes you need to again loop through the options array which is 1 level.
then you reach the thrid level which is your output.
Third level means starting from zero its second level.
I hope this will solve the issue.
var data = [
{
"name": "0th level first", //0th level
"options": [
{
"name": "1st level Cafe", // 1st level
"options": [
{
"name": "2nd level Staff", //2nd level
"options": [
{
"name": "Gary", //3rd level
"age": 18
},
{
"name": "James", //3rd level
"age": 25
}
]
}
]
}
]
}
]
data.forEach(fl => {
fl.options.forEach(sl => {
sl.options.forEach(tl => {
console.log("second level starting from 0",tl)
})
})
})
Assume data contains your json, we have 2 onliners:
let out = data[0].options[0].options[0];
let outArr = data.flatMap(x=>x.options.flatMap(y=>y.options));
results
// out = {"name":"2nd level Staff","options":[{"name":"Gary","age":18},{"name":"James","age":25}]}
// outArr = [{"name":"2nd level Staff","options":[{"name":"Gary","age":18},{"name":"James","age":25}]}]
First one (out) contains one 2nd element. We use here tree indexes here (three zeros) first data[0] return first element in array data, then options[0] return first element in options array.
The second solution (outArr) contains array of all 2nd elements. We use here JS flatMap
To write second solution inspired me abdullahkady comment below question.

Get the last elements in a JSON array in Javascript

I have a JSON array like this:
[
{
"id": "1",
"name": "A"
},
{
"id": "2",
"name": "B"
},
{
"id": "3",
"name": "C"
},
{
"id": "4",
"name": "D"
},
....
....
{
"id": "n",
"name": "X"
}
]
I'm looking for a slice() based function that gives the last 20 item of this JSON array
function getLast(array,x){return array.slice(array.length-x)}
Just use the slice function starting with the array length minus the number of elements you want to extract.
A simple way with filters:
filteredList = list.filter((_, index) => {
return index >= list.length - 20
})
If you just need the last X items in an array I'm not sure you need filter, you can use .slice eg [1,2,3,4,5,6,7,8,9,10].slice(-5) will return [6,7,8,9,10]
One option is to use splice or slice:
// Initialize array
let arr = new Array(50).fill().map((v,i)=>i)
// Pick off last 20 elements
console.log('Last:' + arr.slice(-20))
Note: splice modifies the existing array; if you don't want to modify the existing array use slice
Another example
let arr = new Array(50).fill().map((v,i)=>i+1) // [1,2,..50]
Array.prototype.last = function(n){
return this.slice(-n)
};
console.log( arr.last(20) )

Combining values in nested objects with common properties

# Problem
Hello. I have a JSON response containing a varying amount of objects (a set of indicators), each containing a fixed set of other objects (geometries) that each contain properties (one of which is 'score').
I'm trying to gather these 'score' properties in order to later do stuff such as min/mean/max by geometry.
# Sample
Here's an example (keeping in mind there could be more than two indicators):
let data = [ {
{
"indicator": "A",
"geom": "1",
"score": 1
},
{
"indicator": "A",
"geom": "2",
"score": 2
} }, {
{
"indicator": "B",
"geom": "1",
"score": 3
},
{
"indicator": "B",
"geom": "2",
"score": 4
} } ]
# Expected result
The result I'm looking for would be something like this, with concatenated values originating from different sub-objects :
let expectedResult = {
{
"indicator": ["A", "B"],
"geom": "1",
"score": [1,3]
},
{
"indicator": ["A", "B],
"geom": "2",
"score": [2,4]
} }
# My (no good) solution
My current, ugly buggy solution is to create an array with all geom ids :
let id = data[0].map(obj => obj.geom);
Then get a complete list of all key-value :
let keyval;
data.map((indic) => { indic.map((geom) =>
{ keyval.push([car.geom, car.score])})});
And finally combine geom id var with values that have identical id (and slice off the redundant id) :
id.map((geom, idx) => {keyval.map((arr) => {
if (car === arr[0]) { id.push(geom, arr.splice(0,1)})
}
})
});
Would anyone know of a more elegant/efficient.. and more importantly working solution ? During my research saw a lot of Array.prototype.reduce(), but didn't figure out how to use it in such a nested configuration.
Thanks,
O.
Use Array#reduce to collect the values into a Map, then use Map#values, and the spread syntax to convert back to an array:
const data = [[{"indicator":"A","geom":"1","score":1},{"indicator":"A","geom":"2","score":2}],[{"indicator":"B","geom":"1","score":3},{"indicator":"B","geom":"2","score":4}]];
const result = [...[].concat(...data).reduce((map, o) => {
const item = map.get(o.geom) || { geom: o.geom, indicator: [], score: [] }; // get the item from the map, or create a new one
item.indicator.push(o.indicator);
item.score.push(o.score);
return map.set(o.geom, item); // set the item and return the map reference
}, new Map).values()]; // get the map values iterator, and use spread (...) to get an array
console.log(result);

Categories

Resources