I have an object with the following structure:
object = { ids: [], labels:[], values:[] }
each key has 80 values. I want to sort the 'values' key in descending order (biggest to smallest), and update the ids and labels keys accordingly (so the label and id of the highest 'values' value is now first). I tried the following code but it doesn't work:
function getSorted(arr, sortArr) {
var result = [];
for(var i=0; i<arr.length; i++) {
console.log(sortArr[i], arr[i]);
result[i] = arr[sortArr[i]];
}
return result;
}
the data I am trying to sort is this:
ids = [41, 121, 159, 165, 170, 189, 258, 259, 307, 340, 342, 352, 357, 412, 482, 513, 725, 830, 833, 874, 907, 944, 1167, 1169, 1189, 1193, 1208, 1232, 1274, 1314, 1497, 1498, 1503, 1505, 1795, 1950, 1959, 1960, 1962, 1968, 1977, 2011, 2024, 2039, 2065, 2077, 2110, 2167, 2178, 2184, 2186, 2188, 2191, 2235, 2244, 2247, 2264, 2275, 2291, 2318, 2335, 2342, 2350, 2396, 2419, 2475, 2483, 2491, 2546, 2571, 2722, 2737, 2739, 2782, 2811, 2859, 2908, 2936, 2964, 3450]
values = [71, 2, 2, 12, 2, 47, 2, 2, 7, 2, 2, 50, 2, 2, 113, 2, 2, 10, 3, 36, 3, 19, 163, 2, 51, 6, 5, 2, 4, 3, 2, 2, 2, 2, 10, 25, 30, 2, 3, 2, 40, 11, 13, 5, 2, 23, 2, 5, 7, 19, 3, 2, 28, 2, 14, 11, 78, 22, 2, 40, 3, 2, 2, 11, 13, 2, 2, 2, 2, 2, 8, 4, 4, 12, 13, 126, 7, 3, 10, 37]
labels = ["Bacteria", "Bacteria", "Bacteria", "Bacteria", "Bacteria", "Bacteria", "Bacteria", "Bacteria", "Bacteria", "Bacteria", "Bacteria", "Bacteria", "Bacteria", "Bacteria", "Bacteria", "Bacteria", "Bacteria;Actinobacteria;Actinobacteria;Actinomycetales", "Bacteria;Actinobacteria;Actinobacteria;Actinomycetales", "Bacteria;Actinobacteria;Actinobacteria;Actinomycetales;Actinomycetaceae", "Bacteria;Actinobacteria;Actinobacteria;Actinomycetales;Actinomycetaceae;Varibaculum", "Bacteria;Actinobacteria;Actinobacteria;Actinomycetales;Corynebacteriaceae", "Bacteria;Actinobacteria;Actinobacteria;Actinomycetales;Corynebacteriaceae;Corynebacterium", "Bacteria;Bacteroidetes;Bacteroidia;Bacteroidales;Porphyromonadaceae;Porphyromonas", "Bacteria;Bacteroidetes;Bacteroidia;Bacteroidales;Porphyromonadaceae;Porphyromonas", "Bacteria;Bacteroidetes;Bacteroidia;Bacteroidales;Porphyromonadaceae;Porphyromonas", "Bacteria;Bacteroidetes;Bacteroidia;Bacteroidales;Porphyromonadaceae;Porphyromonas", "Bacteria;Bacteroidetes;Bacteroidia;Bacteroidales;Porphyromonadaceae;Porphyromonas", "Bacteria;Bacteroidetes;Bacteroidia;Bacteroidales;Porphyromonadaceae;Porphyromonas", "Bacteria;Bacteroidetes;Bacteroidia;Bacteroidales;Prevotellaceae", "Bacteria;Bacteroidetes;Bacteroidia;Bacteroidales;Prevotellaceae;Prevotella", "Bacteria;Firmicutes", "Bacteria;Firmicutes", "Bacteria;Firmicutes", "Bacteria;Firmicutes", "Bacteria;Firmicutes;Bacilli;Bacillales;Staphylococcaceae;Staphylococcus", "Bacteria;Firmicutes;Clostridia", "Bacteria;Firmicutes;Clostridia", "Bacteria;Firmicutes;Clostridia", "Bacteria;Firmicutes;Clostridia", "Bacteria;Firmicutes;Clostridia", "Bacteria;Firmicutes;Clostridia;Clostridiales", "Bacteria;Firmicutes;Clostridia;Clostridiales", "Bacteria;Firmicutes;Clostridia;Clostridiales", "Bacteria;Firmicutes;Clostridia;Clostridiales", "Bacteria;Firmicutes;Clostridia;Clostridiales", "Bacteria;Firmicutes;Clostridia;Clostridiales", "Bacteria;Firmicutes;Clostridia;Clostridiales", "Bacteria;Firmicutes;Clostridia;Clostridiales", "Bacteria;Firmicutes;Clostridia;Clostridiales", "Bacteria;Firmicutes;Clostridia;Clostridiales;IncertaeSedisXI", "Bacteria;Firmicutes;Clostridia;Clostridiales;IncertaeSedisXI", "Bacteria;Firmicutes;Clostridia;Clostridiales;IncertaeSedisXI", "Bacteria;Firmicutes;Clostridia;Clostridiales;IncertaeSedisXI", "Bacteria;Firmicutes;Clostridia;Clostridiales;IncertaeSedisXI", "Bacteria;Firmicutes;Clostridia;Clostridiales;IncertaeSedisXI", "Bacteria;Firmicutes;Clostridia;Clostridiales;IncertaeSedisXI", "Bacteria;Firmicutes;Clostridia;Clostridiales;IncertaeSedisXI", "Bacteria;Firmicutes;Clostridia;Clostridiales;IncertaeSedisXI", "Bacteria;Firmicutes;Clostridia;Clostridiales;IncertaeSedisXI", "Bacteria;Firmicutes;Clostridia;Clostridiales;IncertaeSedisXI;Anaerococcus", "Bacteria;Firmicutes;Clostridia;Clostridiales;IncertaeSedisXI;Anaerococcus", "Bacteria;Firmicutes;Clostridia;Clostridiales;IncertaeSedisXI;Anaerococcus", "Bacteria;Firmicutes;Clostridia;Clostridiales;IncertaeSedisXI;Anaerococcus", "Bacteria;Firmicutes;Clostridia;Clostridiales;IncertaeSedisXI;Anaerococcus", "Bacteria;Firmicutes;Clostridia;Clostridiales;IncertaeSedisXI;Anaerococcus", "Bacteria;Firmicutes;Clostridia;Clostridiales;IncertaeSedisXI;Anaerococcus", "Bacteria;Firmicutes;Clostridia;Clostridiales;IncertaeSedisXI;Anaerococcus", "Bacteria;Firmicutes;Clostridia;Clostridiales;IncertaeSedisXI;Anaerococcus", "Bacteria;Firmicutes;Clostridia;Clostridiales;IncertaeSedisXI;Anaerococcus", "Bacteria;Firmicutes;Clostridia;Clostridiales;IncertaeSedisXI;Anaerococcus", "Bacteria;Firmicutes;Clostridia;Clostridiales;IncertaeSedisXI;Finegoldia", "Bacteria;Firmicutes;Clostridia;Clostridiales;IncertaeSedisXI;Gallicola", "Bacteria;Firmicutes;Clostridia;Clostridiales;IncertaeSedisXI;Gallicola", "Bacteria;Firmicutes;Clostridia;Clostridiales;IncertaeSedisXI;Peptoniphilus", "Bacteria;Firmicutes;Clostridia;Clostridiales;IncertaeSedisXI;Peptoniphilus", "Bacteria;Firmicutes;Clostridia;Clostridiales;IncertaeSedisXI;Peptoniphilus", "Bacteria;Firmicutes;Clostridia;Clostridiales;Peptococcaceae;Peptococcus", "Bacteria;Firmicutes;Clostridia;Clostridiales;Ruminococcaceae", "Bacteria;Firmicutes;Clostridia;Clostridiales;Veillonellaceae", "Bacteria;Proteobacteria;Epsilonproteobacteria;Campylobacterales;Campylobacteraceae;Campylobacter"]
How should I tackle this problem? Thanks
The only relationship you have between the three sets of data is the index inside of each array, which will be lost when you sort. To keep the three sets of data paired, I would map over your data and create an object for each:
const data = { ids, labels, values };
const list = data.values.map((value, idx) => {
return {
id: data.ids[idx],
value,
label: data.labels[idx]
};
});
Now list contains an array of objects:
[
{
id: 41,
label: 'Bacteria',
value: '71',
},
{
// ... etc
}
]
This is a much easier data structure to work with because you want id, label, and value to remain paired together.
At that point, you can easily sort this array of objects by the value property descending like so:
list.sort((a, b) => {
return b.value - a.value;
});
And now list is an array of objects of your data, sorted by object.value descending.
You can use this array of objects, or translate it back into your original format of three different arrays easily.
I know it's a little different from what you asked, but maybe you can have an idea on how to adapt for your needs.
While ago I made this function to solve a sorting problems on my objects.
function sortObj(obj, index, sorting) {
let ans = [];
sorting = sorting.toUpperCase();
if (obj.constructor === Array) {
for (let i=0; i < obj.length; i++) {
ans.push(obj[i]);
}
}
else {
for (let k in obj) {
if (obj.hasOwnProperty(k)) {
ans.push(obj[k])
}
}
}
if (!ans.length)
return [];
if (isNaN(ans[0][index])) {
ans = ans.sort(function (a,b) {
if (a[index]) {
if (sorting === "ASC")
return a[index].localeCompare(b[index]);
else
return b[index].localeCompare(a[index]);
}
return [];
});
}
else {
ans = ans.sort(function (a, b) {
if (sorting === "ASC")
return a[index] - b[index];
else
return b[index] - a[index];
})
}
return ans;
}
// structure of object
obj = {"1": {id: "1", label: "A", value: "5"}, "2": {id: "2", label: "B", value: "1"}}
sorted = sortObj(obj, "label", "ASC");
// [{id: "1", label: "A", value: "5"}, {id: "2", label: "B", value: "1"}]
sorted = sortObj(obj, "value", "ASC");
// [{id: "2", label: "B", value: "1"}, {id: "1", label: "A", value: "5"}]
Related
This is how I get the data:
const dataSaved = [{
count: 52,
deliveryAmount: 0,
discountAmount: 7,
guests: 2,
refundedAmount: 9,
serviceChargeAmount: 4,
storeId: "aslkasad",
subtotal: 2,
taxAmount: 4,
total: 3
}, {
count: 52,
deliveryAmount: 0,
discountAmount: 7,
guests: 2,
refundedAmount: 9,
serviceChargeAmount: 4,
storeId: "ldfgfgdf",
subtotal: 2,
taxAmount: 4,
total: 3
}]
So basically I have made a method in which I'm filtering an array of objects and just taking out the fields I need:
getDataParsed(dataSaved, storeFieldRequired) {
const barData = [];
for (const store of dataSaved) {
barData.push({
data: [store.storeFieldRequired],
label: store.storeId
});
}
return barData;
}
When I want to get an specific field of the array, my [store.storeFieldRequired] brings undefined.
How can I solve it?
Instead of using store.storeFieldRequired, it is needed to use store[storeFieldRequired]. They have different meanings.
store.storeFieldRequired means to get the value of storeFieldRequired key on store object.
store[storeFieldRequired] means to get the value of storeFieldRequired variable value key on store object.
const dataSaved = [{
count: 52,
deliveryAmount: 0,
discountAmount: 7,
guests: 2,
refundedAmount: 9,
serviceChargeAmount: 4,
storeId: "aslkasad",
subtotal: 2,
taxAmount: 4,
total: 3
}, {
count: 52,
deliveryAmount: 0,
discountAmount: 7,
guests: 2,
refundedAmount: 9,
serviceChargeAmount: 4,
storeId: "ldfgfgdf",
subtotal: 2,
taxAmount: 4,
total: 3
}];
function getDataParsed(dataSaved, storeFieldRequired) {
const barData = [];
for (const store of dataSaved) {
barData.push({
data: [store[storeFieldRequired]],
label: store.storeId
});
}
return barData;
}
console.log(getDataParsed(dataSaved, 'count'));
Simply, using Array.prototype.map, you can get the result.
const dataSaved = [{
count: 52,
deliveryAmount: 0,
discountAmount: 7,
guests: 2,
refundedAmount: 9,
serviceChargeAmount: 4,
storeId: "aslkasad",
subtotal: 2,
taxAmount: 4,
total: 3
}, {
count: 52,
deliveryAmount: 0,
discountAmount: 7,
guests: 2,
refundedAmount: 9,
serviceChargeAmount: 4,
storeId: "ldfgfgdf",
subtotal: 2,
taxAmount: 4,
total: 3
}];
function getDataParsed(dataSaved, storeFieldRequired) {
return dataSaved.map((item) => ({
data: [item[storeFieldRequired]],
label: item.storeId
}));
}
console.log(getDataParsed(dataSaved, 'count'));
Access the variable with bracket-[] notation. Example => data: [store[storeFieldRequired]].
getDataParsed(storeData, storeFieldRequired) {
const barData = [];
for (const store of storeData) {
barData.push({
data: [store[storeFieldRequired]], // change this line from data: [store.storeFieldRequired] to data: [store[storeFieldRequired]]
label: store.storeId
});
}
return barData;
}
I have an array of objects that I want to reduce into a single object. The sample array always has the same keys in each of its objects as seen below:
sample = [
{australia: 0, belgium: 0, brazil: 0, canada: 1, china: 1, ...},
{australia: 0, belgium: 0, brazil: 3, canada: 2, china: 2, ...},
{australia: 2, belgium: 1, brazil: 4, canada: 2, china: 5, ...}
]
I am looking to obtain a single object where the keys are the same as in the objects, and the values are a concatenation of each value in the initial array.
Something like this:
desiredResult: {australia:[0,0,2],belgium:[0,0,1],brazil:[0,3,4],canada:[1,2,2],china:[1,2,5],...}
So far I have been trying the following reduce method on the array, but I am missing the part where I concatenate all the values:
let desiredResult = sample.reduce((a,b) =>({...a, desiredResult: b}),{})
// Which results in:
// desiredResult: {australia: 2, belgium: 1, brazil: 4, canada: 2, china: 5}
¿Could you help me figure out the best way to reach this solution?
You could get the entries and create new properties as array and push the value to it.
var sample = [{ australia: 0, belgium: 0, brazil: 0, canada: 1, china: 1 }, { australia: 0, belgium: 0, brazil: 3, canada: 2, china: 2 }, { australia: 2, belgium: 1, brazil: 4, canada: 2, china: 5 }],
result = sample.reduce((r, o) => {
Object.entries(o).forEach(([k, v]) => (r[k] = r[k] || []).push(v));
return r;
}, {});
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Since each of the lement in the array is again a object , you need to iterate them
let sample = [{
'australia': 0,
'belgium': 0,
'brazil': 0,
'canada': 1,
'china': 1
},
{
'australia': 0,
'belgium': 0,
'brazil': 3,
'canada': 2,
'china': 2
},
{
'australia': 2,
'belgium': 1,
'brazil': 4,
'canada': 2,
'china': 5
}
];
let newData = sample.reduce((acc, curr) => {
for (let keys in curr) {
if (!acc[keys]) {
acc[keys] = []
}
acc[keys].push(curr[keys])
}
return acc;
}, {});
console.log(newData)
You can try reduce by taking entries of element in key, value form and then pushing them using for..of in accumulator accordingly:
var sample = [{ australia: 0, belgium: 0, brazil: 0, canada: 1, china: 1 }, { australia: 0, belgium: 0, brazil: 3, canada: 2, china: 2 }, { australia: 2, belgium: 1, brazil: 4, canada: 2, china: 5 }]
const result= sample.reduce((acc, elem)=>{
countries= Object.entries(elem);
for(const [country, count] of countries){
acc[country]= acc[country] || [];
acc[country].push(count);
}
return acc;
},{});
console.log(result);
Having an array like this:
const data = [
{
"name": "Dave",
"coins": 14,
"weapons": 2,
"otherItems": 3,
"color": "red"
},
{
"name": "Vanessa",
"coins": 18,
"weapons": 1,
"otherItems": 5,
"color": "blue"
},
{
"name": "Sharon",
"coins": 9,
"weapons": 5,
"otherItems": 1,
"color": "pink"
},
{
"name": "Walter",
"coins": 9,
"weapons": 2,
"otherItems": 4,
"color": "white"
}
]
How to count sum of coins, weapons and otherItems using ES6 features? (I'm not attached to this: any simple method would be good.)
data.reduce((first, last) => first + last) generates a chain of [object Object][object Object]s...
You have to process every field separately (note that when you don't specify second parameter for reduce it will take first array object as seed and start processing from the second one):
const data = [
{
"name": "Dave",
"coins": 14,
"weapons": 2,
"otherItems": 3,
"color": "red"
},
{
"name": "Vanessa",
"coins": 18,
"weapons": 1,
"otherItems": 5,
"color": "blue"
},
{
"name": "Sharon",
"coins": 9,
"weapons": 5,
"otherItems": 1,
"color": "pink"
},
{
"name": "Walter",
"coins": 9,
"weapons": 2,
"otherItems": 4,
"color": "white"
}
]
let result = data.reduce((a,c)=> ({
coins: a.coins + c.coins,
weapons: a.weapons + c.weapons,
otherItems: a.otherItems + c.otherItems })
)
console.log(result);
You could take an array of wanted keys for the sums and create an object for the sums and add the wanted values.
const
data = [{ name: "Dave", coins: 14, weapons: 2, otherItems: 3, color: "red" }, { name: "Vanessa", coins: 18, weapons: 1, otherItems: 5, color: "blue" }, { name: "Sharon", coins: 9, weapons: 5, otherItems: 1, color: "pink" }, { name: "Walter", coins: 9, weapons: 2, otherItems: 4, color: "white" }],
keys = ['coins', 'weapons', 'otherItems'],
sums = data.reduce(
(r, o) => (keys.forEach(k => r[k] += o[k]), r),
Object.fromEntries(keys.map(k => [k, 0]))
);
console.log(sums);
You can use Array.prototype.reduce for this.
To make it a little bit more flexible and dynamic, make a Set of keys you want to get a count of.
Then go through each key in the Set and if that key is in the obj, sum it up in an accumulator object in the reduce callback:
const data = [{"name":"Dave","coins":14,"weapons":2,"otherItems":3,"color":"red"},{"name":"Vanessa","coins":18,"weapons":1,"otherItems":5,"color":"blue"},{"name":"Sharon","coins":9,"weapons":5,"otherItems":1,"color":"pink"},{"name":"Walter","coins":9,"weapons":2,"otherItems":4,"color":"white"}]
//Keys to count
const keys = new Set(["coins", "weapons", "otherItems"]);
const count = data.reduce((acc, obj) => {
const objKeys = keys.forEach(key => {
if (obj.hasOwnProperty(key)) {
acc[key] = (acc[key] || 0) + obj[key];
}
});
return acc;
}, {});
console.log(count);
Your idea is right, you need to use reduce method. The problem is that you're summing two objects, not their properties. All you need to do is change the code to the following (to sum the coins):
data.reduce((first, last) => first.coins + last.coins, 0)
And following for weapons:
data.reduce((first, last) => first.weapons + last.weapons, 0)
Below is my input:
input1 =
[{
"201609": 5,
"201610": 7,
"201611": 9,
"201612": 10,
"FY17": 24,
"metric": "metric1",
"careerLevelGroups": [{
"201609": 3,
"201610": 6,
"201611": 9,
"201612": 8
"FY17": 18,
"careerLevel": "Senior Managing Director",
"careerLevels": [{
"201609": 1,
"201610": 2,
"201611": 3,
"201612": 5
"FY17": 6,
"careerLevel": "CL1"
},
{
"201609": 2,
"201610": 4,
"201611": 6,
"201612": 9
"FY17": 12,
"careerLevel": "CL2"
}
]
}]
}]
input2 =
[{
"201609": 4,
"201610": 8,
"201611": 12,
"FY17": 24,
"metric": "metric1",
"careerLevelGroups": [{
"201609": 9,
"201610": 2,
"201611": 7,
"FY17": 18,
"careerLevel": "Senior Managing Director",
"careerLevels": [{
"201609": 3,
"201610": 6,
"201611": 9,
"FY17": 18,
"careerLevel": "CL1"
},
{
"201609": 7,
"201610": 8,
"201611": 9,
"FY17": 24,
"careerLevel": "CL2"
}
]
}]
}]
output = input1 + input2.
My output should have the sum of all the numeric value. If it doesn't
find the matching key like "201612" it should still keep that key in
output.
[{
"201609": 9,
"201610": 15,
"201611": 21,
"201612": 10,
"FY17": 48,
"metric": "metric1",
"careerLevelGroups": [{
"201609": 12,
"201610": 8,
"201611": 16,
"201612": 8,
"FY17": 24,
"careerLevel": "Senior Managing Director",
"careerLevels": [{
"201609": 4,
"201610": 8,
"201611": 12,
"201612": 5,
"FY17": 24,
"careerLevel": "CL1"
},
{
"201609": 9,
"201610": 12,
"201611": 15,
"201612": 9,
"FY17": 36,
"careerLevel": "CL2"
}
]
}]
}]
Below is what iam trying to do :
var output = [{}];
for(let i in input){
for (let key in input[i]){
if (output[0].hasOwnProperty(key)) {
output[0][key]+=input[i][key];
}else{
output[0][key]=input[i][key];
}
}
}
console.log(JSON.stringify(output)); // errors out
But this is not giving me desired result as it is not able to sum the hierarchical json structure as above.
Let's start by writing the main merge function:
function merge(x, y, fn) {
if (isNotCompound(x) && isNotCompound(y)) {
return fn(x, y);
}
if (isArray(x) && isArray(y)) {
return mergeArray(x, y, fn);
}
if (isObject(x) && isObject(y)) {
return mergeObject(x, y, fn);
}
throw new Error('the two input values are not of the same compound type');
}
The merge function amounts to a dispatching on the type of its input values x and y. If they are both found to be primitive types (i.e., they are not arrays nor objects) they are merged according to the fn function. Otherwise, the proper helper function is selected for proceeding with the traversing.
Let's therefore implement the type predicates necessary for the dispatch:
const isArray = x => Array.isArray(x);
const isObject = x => Object.prototype.toString.call(x) === '[object Object]';
const isNotCompound = x => !isArray(x) && !isObject(x);
It is now a matter of writing mergeArray and mergeObject. One possible implementation for mergeArray is as follows:
function mergeArray(xs, ys, fn) {
if (xs.length !== ys.length) throw new Error('the two arrays must be of the same size');
let r = [];
for (let i = 0; i < xs.length; i++) {
r.push(merge(xs[i], ys[i], fn));
}
return r;
}
As shown, mergeArray requires the two arrays of being of the same size. As for mergeObject, one way of implementing it is as follows:
function mergeObject(obj1, obj2, fn) {
let r = {};
for (let key of Object.keys(obj1)) {
r[key] = obj2[key] ? merge(obj1[key], obj2[key], fn) : obj1[key];
}
for (let key of Object.keys(obj2)) {
if (r[key]) continue;
r[key] = obj2[key];
}
return r;
}
Notably, values are combined for common keys, while unshared properties are directly propagated to the resulting object.
At last, the desired merging strategy can be obtained by passing the following input function:
const isNumber = x => typeof x === 'number';
const add = (x, y) => isNumber(x) && isNumber(y) ? x + y : (x || y);
If the two input, primitive values are both numbers, it returns the sum of them, otherwise it returns whatever of the two happens to be defined.
We can finally execute:
console.log(JSON.stringify(merge(input1, input2, add)));
The whole source code follows.
const isArray = x => Array.isArray(x);
const isObject = x => Object.prototype.toString.call(x) === '[object Object]';
const isNotCompound = x => !isArray(x) && !isObject(x);
function merge(x, y, fn) {
if (isNotCompound(x) && isNotCompound(y)) {
return fn(x, y);
}
if (isArray(x) && isArray(y)) {
return mergeArray(x, y, fn);
}
if (isObject(x) && isObject(y)) {
return mergeObject(x, y, fn);
}
throw new Error('the two input values are not of the same compound type');
};
function mergeArray(xs, ys, fn) {
if (xs.length !== ys.length) throw new Error('the two arrays must be of the same size');
let r = [];
for (let i = 0; i < xs.length; i++) {
r.push(merge(xs[i], ys[i], fn));
}
return r;
}
function mergeObject(obj1, obj2, fn) {
let r = {};
for (let key of Object.keys(obj1)) {
r[key] = obj2[key] ? merge(obj1[key], obj2[key], fn) : obj1[key];
}
for (let key of Object.keys(obj2)) {
if (r[key]) continue;
r[key] = obj2[key];
}
return r;
}
let input1 = [{
"201609": 5,
"201610": 7,
"201611": 9,
"201612": 10,
"FY17": 24,
"metric": "metric1",
"careerLevelGroups": [{
"201609": 3,
"201610": 6,
"201611": 9,
"201612": 8,
"FY17": 18,
"careerLevel": "Senior Managing Director",
"careerLevels": [{
"201609": 1,
"201610": 2,
"201611": 3,
"201612": 5,
"FY17": 6,
"careerLevel": "CL1"
},
{
"201609": 2,
"201610": 4,
"201611": 6,
"201612": 9,
"FY17": 12,
"careerLevel": "CL2"
}
]
}]
}];
let input2 = [{
"201609": 4,
"201610": 8,
"201611": 12,
"FY17": 24,
"metric": "metric1",
"careerLevelGroups": [{
"201609": 9,
"201610": 2,
"201611": 7,
"FY17": 18,
"careerLevel": "Senior Managing Director",
"careerLevels": [{
"201609": 3,
"201610": 6,
"201611": 9,
"FY17": 18,
"careerLevel": "CL1"
}, {
"201609": 7,
"201610": 8,
"201611": 9,
"FY17": 24,
"careerLevel": "CL2"
}]
}]
}];
const isNumber = x => typeof x === 'number';
const add = (x, y) => isNumber(x) && isNumber(y) ? x + y : (x || y);
console.log(JSON.stringify(merge(input1, input2, add)));
Create a recursive function and inside that use forEach to iterate the array
The flow is like this instead of looping both the input1 & input2 array , loop over one of them and if the value of the key is an number then add it to the value of same key in another array.If the value of a key is an array then call the same recursive function with new arguuments
var input1 = [{
"201609": 5,
"201610": 7,
"201611": 9,
"201612": 10,
"FY17": 24,
"metric": "metric1",
"careerLevelGroups": [{
"201609": 3,
"201610": 6,
"201611": 9,
"201612": 8,
"FY17": 18,
"careerLevel": "Senior Managing Director",
"careerLevels": [{
"201609": 1,
"201610": 2,
"201611": 3,
"201612": 5,
"FY17": 6,
"careerLevel": "CL1"
},
{
"201609": 2,
"201610": 4,
"201611": 6,
"201612": 9,
"FY17": 12,
"careerLevel": "CL2"
}
]
}]
}]
var input2 = [{
"201609": 4,
"201610": 8,
"201611": 12,
"FY17": 24,
"metric": "metric1",
"careerLevelGroups": [{
"201609": 9,
"201610": 2,
"201611": 7,
"FY17": 18,
"careerLevel": "Senior Managing Director",
"careerLevels": [{
"201609": 3,
"201610": 6,
"201611": 9,
"FY17": 18,
"careerLevel": "CL1"
},
{
"201609": 7,
"201610": 8,
"201611": 9,
"FY17": 24,
"careerLevel": "CL2"
}
]
}]
}]
// A function which will take input2 and input1 array
function loopArray(arrayToBeLooped, addingArray) {
// now looping over the array
arrayToBeLooped.forEach(function(item, index) {
// item is each object,here checking if the value of object key is array or number
for (let keys in item) {
// if number then find the same key from other array and add the value
if (typeof item[keys] === 'number') {
addingArray[index][keys] = addingArray[index][keys] + item[keys]
}
if (Array.isArray(item[keys])) {
// if the type of value is another array for example
// careerLevelGroups & careerLevels then it is basically same
// as looping over array input1 & input2
// so calling the same loopArray function and passing different
// parameter but the object remains same
loopArray(arrayToBeLooped[index][keys], addingArray[index][keys])
}
}
})
}
loopArray(input2, input1)
console.log(input1)
var json =
[
{
id: 11,
name:"app1",
family:"apps",
caseID: 123,
order:1
},
{
id: 12,
name:"app1",
family:"apps",
caseID: 123,
order:2
},
{
id: 13,
name:"app1",
family:"apps",
caseID: 123,
order:3
},
{
id: 14,
name:"app2",
family:"tools",
caseID: 129,
order:1
},
{
id: 15,
name:"app2",
family:"tools",
caseID: 129,
order:2
},
{
id: 16,
name:"app3",
family:"utils",
caseID: 120,
order:1
},
{
id: 17,
name:"app3",
family:"utils",
caseID: 120,
order:2
},
id: 18,
name:"app3",
family:"utils",
caseID: 150,
order:null
}
]
Hello, I would like to sort the array above by the highest "order" key and return the filtered array below. The common key is the caseID. Also, If the order key is null return it.
I've searched and tested some functions and loops but cannot seem to get it rite. Any help will be much appreciated. I'd prefer es2015 if possible.
Thank you!
filtered =
[
{
id: 13,
name:"app1",
family:"apps",
caseID: 123,
order:3
},
{
id: 15,
name:"app2",
family:"tools",
caseID: 129,
order:2
},
{
id: 17,
name:"app3",
family:"utils",
caseID: 120,
order:2
},
{
id: 18,
name:"app3",
family:"utils",
caseID: 150,
order:null
}
]
I would start by getting rid of dupes. You can do this with reduce() and assigning to an object keyed to caseID. You can simultaneously avoid any object with a smaller order than one you've already seen. Then you can take the values of that hash which will be the unique objects base on caseID and sort them like you normally would. For example:
var json = [{ "id": 11, "name":"app1", "family":"apps", "caseID": 123, "order":1},{ "id": 12, "name":"app1", "family":"apps", "caseID": 123, "order":2},{ "id": 13, "name":"app1", "family":"apps", "caseID": 123, "order":3},{ "id": 14, "name":"app2", "family":"tools", "caseID": 129, "order":1},{ "id": 15, "name":"app2", "family":"tools", "caseID": 129, "order":2},{ "id": 16, "name":"app3", "family":"utils", "caseID": 120, "order":1},{ "id": 17, "name":"app3", "family":"utils", "caseID": 120, "order":2},{ "id": 18, "name":"app3", "family":"utils", "caseID": 150, "order":null},]
// get just the filtered items based on caseID
// picking out only the largest
let filtered = json.reduce((a,c) => {
if (!a[c.caseID] || a[c.caseID]['order'] < c.order) a[c.caseID] = c
return a
}, {})
// basic sort
let result = Object.values(filtered).sort((a,b) => b.order - a.order)
console.log(result)
You could use a caseID hashtable and override results you find later if order is higher:
const result = [], hash = {};
for(const el in json) {
const exists = hash[el.caseId];
if(exists) {
if(el.order > exists.order)
Object.assign(exists, el);
} else {
result.push(hash[el.caseId] = {...el});
}
}
You can try following
Method
Create an object with unique case ID as key and value being the item with highest order
Sort based on order
// Code goes here
var json = [{"id":11,"name":"app1","family":"apps","caseID":123,"order":1},{"id":12,"name":"app1","family":"apps","caseID":123,"order":2},{"id":13,"name":"app1","family":"apps","caseID":123,"order":3},{"id":14,"name":"app2","family":"tools","caseID":129,"order":1},{"id":15,"name":"app2","family":"tools","caseID":129,"order":2},{"id":16,"name":"app3","family":"utils","caseID":120,"order":1},{"id":17,"name":"app3","family":"utils","caseID":120,"order":2},{"id":18,"name":"app3","family":"utils","caseID":150,"order":null}];
var map = {};
// Create a map of unique case ID's with highest order
json.forEach((item) => {
if(map[item.caseID]) {
if(map[item.caseID].order < item.order) {
map[item.caseID] = item;
}
} else {
map[item.caseID] = item;
}
});
// Sorting the array based on order
var result = Object.values(map).sort((a,b) => b.order-a.order);
console.log(result);
In ES6:
json.sort((a, b) => a.caseID > b.caseID);
let bad_order = json.filter(v => v.order === null);
let good_order = json.filter(v => v.order !== null);
Example
In ES5:
json.sort(function(a, b) { return a.caseID > b.caseID; });
var bad_order = [];
var good_order = [];
for(var i = 0; i < json.length; i++){
if(json[i].order === null)
bad_order.push(json[i]);
else
good_order.push(json[i]);
}
Example
Use reduce method to create an object where the keys will be the caseID.While creating the object check if the value of the order is more or less that the current order value.If the current value is less the than the new value, replace it with new value.
Then use Object.values(object) to create an array of values from the object
var json = [{
"id": 11,
"name": "app1",
"family": "apps",
"caseID": 123,
"order": 1
},
{
"id": 12,
"name": "app1",
"family": "apps",
"caseID": 123,
"order": 2
},
{
"id": 13,
"name": "app1",
"family": "apps",
"caseID": 123,
"order": 3
},
{
"id": 14,
"name": "app2",
"family": "tools",
"caseID": 129,
"order": 1
},
{
"id": 15,
"name": "app2",
"family": "tools",
"caseID": 129,
"order": 2
},
{
"id": 16,
"name": "app3",
"family": "utils",
"caseID": 120,
"order": 1
},
{
"id": 17,
"name": "app3",
"family": "utils",
"caseID": 120,
"order": 2
}, {
"id": 18,
"name": "app3",
"family": "utils",
"caseID": 150,
"order": null
}
]
var m = json.reduce(function(acc, curr, index) {
if (acc[curr['caseID']] === undefined) {
acc[curr['caseID']] = curr;
} else {
if (acc[curr['caseID']].order < curr.order) {
acc[curr['caseID']] = curr;
}
}
return acc;
}, {})
console.log(Object.values(m))
This should help you filter array of objects.
var filteredMap = {};
json.forEach(function (item) {
filteredMap[item.caseID] = item;
});
var filteredArray = [];
for (var key in filteredMap) {
filteredArray.push(filteredMap[key]);
}
console.log(JSON.stringify(filteredArray));
Sort by order and caseID and then filter by caseID,Here is the code:
var json =
[
{
id: 11,
name:"app1",
family:"apps",
caseID: 123,
order:1
},
{
id: 12,
name:"app1",
family:"apps",
caseID: 123,
order:2
},
{
id: 13,
name:"app1",
family:"apps",
caseID: 123,
order:3
},
{
id: 14,
name:"app2",
family:"tools",
caseID: 129,
order:1
},
{
id: 15,
name:"app2",
family:"tools",
caseID: 129,
order:2
},
{
id: 16,
name:"app3",
family:"utils",
caseID: 120,
order:1
},
{
id: 17,
name:"app3",
family:"utils",
caseID: 120,
order:2
}, {
id: 18,
name:"app3",
family:"utils",
caseID: 150,
order:null
}
]
var obj = {}
var arr = json.sort(function(a, b) {
return b.order - a.order
}).sort(function(a, b) {
return a.caseId - b.caseId
}).filter(function(item, index, array){
return obj.hasOwnProperty(item.caseID) ? false : (obj[item.caseID] = true)
})
console.log(arr)
demo: http://jsbin.com/qabehorike/edit?js,console,output