Reputation: 147
I created a nested object that holds the following format:
var lineMap = {
2016: {
Hemoglobin: 33 ,
Lysozyme: 33 ,
Myoglobin: 47 ,
DNA: 13 ,
Cytochrome C: 33
},
2017: {
Hemoglobin: 8 ,
Lysozyme: 47 ,
Myoglobin: 8 ,
DNA: 12 ,
Cytochrome C: 33
},
2018: {
Hemoglobin: 8 ,
Lysozyme: 33 ,
Myoglobin: 47 ,
DNA: 12 ,
Cytochrome C: 13
},
2019: {
Hemoglobin: 8 ,
Lysozyme: 8 ,
Myoglobin: 47 ,
DNA: 8 ,
Cytochrome C: 47
}
}
And I'd like to place each year's item count into its own index of an array such that:
var arr = [
[33, 33, 47, 13, 33],
[8, 47, 8, 12, 33],
[8, 33, 47, 12, 13],
[8, 8, 47, 8, 47]
]
I have tried with creating a nested for loop to iterate through the nested object lineMap
.
for (var i = 0; i < year.length; i ++){
for (var j = 0; j < itemName.length; j++){
temp_arr[j] = lineMap[year[i]][itemName[j]];
}
console.log("Index: " + i + "\n" + temp_arr);
arr[i] = temp_arr;
}
console.log(arr);
At the 5th line (console.log(temp_arr)
), the console printed out what I expected--an array of the item count of its respective iteration:
'Index: 0
33,33,47,13,33'
'Index: 1
8,47,8,12,33'
'Index: 2
8,33,47,12,13'
'Index: 3
8,8,47,8,47'
However, at the 8th line (console.log(arr)
), I am not receiving my expected output. Instead, I am getting:
var arr = [
[8, 8, 47, 8, 47],
[8, 8, 47, 8, 47],
[8, 8, 47, 8, 47],
[8, 8, 47, 8, 47]
]
Upvotes: 2
Views: 234
Reputation: 27
I created a function called yearsItemCount(); Just call this and it will return what you want... Although it's O(N^2)
yearsItemCount = () => {
let finalArr = []
for(var line in lineMap) {
let arr = [];
for(var i in lineMap[line]) {
arr.push(lineMap[line][i])
}
finalArr.push(arr);
}
return finalArr;
}
or
Object.values(lineMap).map((a, b) => {
return Object.values(a);
})
I don't know what's faster.
Upvotes: 0
Reputation: 1074188
First, a warning: The order of the properties in those objects is defined, now, as of ES2015, but relying on that order is generally a bad idea. Also, you seem to be using only ES5 level features, which don't define the order.
So the best way, without relying on order, is to give yourself an array of the property names in the order you want them in your result arrays:
var keys = [
"Hemoglobin",
"Lysozyme",
"Myoglobin",
"DNA",
"Cytochrome C"
];
Then something like this (see comments):
// Loop through the years sorted lexicographically, building the result array
var arr = Object.keys(lineMap).sort().map(function(mainKey) {
// Loop through the property names in the defined order, building
// each inner array
var entry = lineMap[mainKey];
return keys.map(function(key) {
return entry[key];
});
});
Live Example:
var keys = [
"Hemoglobin",
"Lysozyme",
"Myoglobin",
"DNA",
"Cytochrome C"
];
var lineMap = {
2016: {
Hemoglobin: 33 ,
Lysozyme: 33 ,
Myoglobin: 47 ,
DNA: 13 ,
"Cytochrome C": 33
},
2017: {
Hemoglobin: 8 ,
Lysozyme: 47 ,
Myoglobin: 8 ,
DNA: 12 ,
"Cytochrome C": 33
},
2018: {
Hemoglobin: 8 ,
Lysozyme: 33 ,
Myoglobin: 47 ,
DNA: 12 ,
"Cytochrome C": 13
},
2019: {
Hemoglobin: 8 ,
Lysozyme: 8 ,
Myoglobin: 47 ,
DNA: 8 ,
"Cytochrome C": 47
}
};
// Loop through the years sorted lexicographically, building the
// result array
var arr = Object.keys(lineMap).sort().map(function(mainKey) {
// Loop through the property names in the defined order, building
// each inner array
var entry = lineMap[mainKey];
return keys.map(function(key) {
return entry[key];
});
});
console.log(arr);
If you want the years in numeric order, just add a callback to the sort
:
.sort(function(a, b) { return a - b; })
Tackling it in an ES2015+ world, I'd still keep the separate list of keys in the order you want them, so not a lot changes, it just gets a bit more concise:
const arr = Object.entries(lineMap)
.sort(([a], [b]) => a.localeCompare(b))
.map(([_, entry]) => keys.map(key => entry[key]));
Live Example:
const keys = [
"Hemoglobin",
"Lysozyme",
"Myoglobin",
"DNA",
"Cytochrome C"
];
const lineMap = {
2016: {
Hemoglobin: 33 ,
Lysozyme: 33 ,
Myoglobin: 47 ,
DNA: 13 ,
"Cytochrome C": 33
},
2017: {
Hemoglobin: 8 ,
Lysozyme: 47 ,
Myoglobin: 8 ,
DNA: 12 ,
"Cytochrome C": 33
},
2018: {
Hemoglobin: 8 ,
Lysozyme: 33 ,
Myoglobin: 47 ,
DNA: 12 ,
"Cytochrome C": 13
},
2019: {
Hemoglobin: 8 ,
Lysozyme: 8 ,
Myoglobin: 47 ,
DNA: 8 ,
"Cytochrome C": 47
}
};
const arr = Object.entries(lineMap)
.sort(([a], [b]) => a.localeCompare(b))
.map(([_, entry]) => keys.map(key => entry[key]));
console.log(arr);
That takes advantage of Object.entries
, arrow functions, and destructuring assignment.
And again, if you want those years in numeric order:
const arr = Object.entries(lineMap)
.sort(([a], [b]) => a - b)
.map(([_, entry]) => keys.map(key => entry[key]));
Upvotes: 1
Reputation: 69286
First of all, you are using the exact same array every time, so when you do arr[i] = temp_arr
you are assigning the same copy to each position of arr
. You should create a new array each time. Secondly, you cannot know the order of an object's keys, there is no guarantee that the keys will be ordered when iterating over them. With this said, you could still use a fixed list of keys or sort them first.
let orderedKeys = ['Hemoglobin', 'Lysozyme', 'Myoglobin', 'DNA', 'Cytochrome C'];
let arr = Object.values(lineMap).map(el => orderedKeys.map(k => el[k]))
Result:
> arr
0: [33, 33, 47, 13, 33]
1: [8, 47, 8, 12, 33]
2: [8, 33, 47, 12, 13]
3: [8, 8, 47, 8, 47]
Upvotes: 0
Reputation: 980
If you're ok with ES6 syntax this will do the trick:
let result = [];
Object.values(lineMap).map(obj =>result.push(Object.values(obj)))
This will get you an array of arrays like you wanted. If you prefer a single array with all the results you can spread the second Object.values(obj)
like so:
Object.values(lineMap).map(obj =>result.push(...Object.values(obj)))
Upvotes: 0
Reputation: 207501
Your issue looks like the problem is with arr[i] = temp_arr;
and sharing the same array reference. You need to start with a new array on each iteration. Or you need to clone it when copying it. arr[i] = temp_arr.slice(0)
Object.entries and map() will make your job easier.
var lineMap = {
2016: {
Hemoglobin: 33,
Lysozyme: 33,
Myoglobin: 47,
DNA: 13,
'Cytochrome C': 33
},
2017: {
Hemoglobin: 8,
Lysozyme: 47,
Myoglobin: 8,
DNA: 12,
'Cytochrome C': 33
},
2018: {
Hemoglobin: 8,
Lysozyme: 33,
Myoglobin: 47,
DNA: 12,
'Cytochrome C': 13
},
2019: {
Hemoglobin: 8,
Lysozyme: 8,
Myoglobin: 47,
DNA: 8,
'Cytochrome C': 47
}
}
console.log(Object.values(lineMap).map(o=>Object.values(o)))
Upvotes: 0