Reputation: 7309
Array of objects with the following properties
[
{ testerId: '1',name:'Kaka'},
{ testerId: '3',name:'Messi'},
{ testerId: '3',name:'Messi'}, // 1 = 3 times (Kaka)
{ testerId: '3',name:'Messi'}, // 2 = 5 times (Ramos)
{ testerId: '3',name:'Messi'}, // 3 = 4 times (Messi)
{ testerId: '2',name:'Ramos'}, // 4 = 2 times (Neuer)
{ testerId: '2',name:'Ramos'}, // 5 = 6 times (Ronaldo)
{ testerId: '1',name:'Kaka'},
{ testerId: '5',name:'Ronaldo'},
{ testerId: '5',name:'Ronaldo'},
{ testerId: '5',name:'Ronaldo'},
{ testerId: '5',name:'Ronaldo'},
{ testerId: '5',name:'Ronaldo'},
{ testerId: '4',name:'Neuer'},
{ testerId: '4',name:'Neuer'},
{ testerId: '1',name:'Kaka'},
{ testerId: '2',name:'Ramos'},
{ testerId: '2',name:'Ramos'},
{ testerId: '2',name:'Ramos'},
{ testerId: '5',name:'Ronaldo'},
]
Output: [Ronaldo
,Ramos
,Messi
,Kaka
,Neuer
]
It's supposed to be in increasing order of occurrence of testerId
.
Upvotes: 1
Views: 2587
Reputation: 350841
You could use Map
to help group by testerId
.
Here is a functional programming style implementation:
const myArray = [{ testerId: '1',name:'Kaka'},{ testerId: '3',name:'Messi'},{ testerId: '3',name:'Messi'},{ testerId: '3',name:'Messi'},{ testerId: '3',name:'Messi'},{ testerId: '2',name:'Ramos'},{ testerId: '2',name:'Ramos'},{ testerId: '1',name:'Kaka'},{ testerId: '5',name:'Ronaldo'},{ testerId: '5',name:'Ronaldo'},{ testerId: '5',name:'Ronaldo'},{ testerId: '5',name:'Ronaldo'},{ testerId: '5',name:'Ronaldo'},{ testerId: '4',name:'Neuer'},{ testerId: '4',name:'Neuer'},{ testerId: '1',name:'Kaka'},{ testerId: '2',name:'Ramos'},{ testerId: '2',name:'Ramos'},{ testerId: '2',name:'Ramos'},{ testerId: '5',name:'Ronaldo'}]
const result = Array.from(
myArray.reduce((map, item) =>
(map.get(item.testerId).count++, map)
, new Map(myArray.map(o =>
[o.testerId, Object.assign({}, o, { count: 0 })]
))), ([k, o]) => o
).sort( (a, b) => b.count - a.count )
.map( o => o.name );
console.log(result);
Some have commented that they find this hard to read. In my opinion this is a matter of habit and once one becomes familiar with it, such code is not so hard to understand.
So here is an explanation:
The first task consists of creating a Map. The Map
constructor can take an array of pairs which represent the keys and values. This array is created from myArray
with the .map()
method. For each object in myArray
, the key testerID
property serves as key, and a copy of the object, extended with a new property count
, serves as the corresponding value. The (shallow) copy is made with Object.assign
This new Map is then passed on to the second argument of the reduce
method, so it becomes the initial value of the reduce
callback function. That callback simply increases the appropriate counter property, and returns the mutated map again (using the comma operator).
The result of this reduce()
call will thus be a map with all the counters set at the right value. This map is then converted back to an array of pairs with Array.from()
. This method can take a callback function which performs a mapping on those key/value pairs. The ([k, o]) => o
mapping just converts the pairs to the value part, throwing the key away.
This array of values (objects with three properties) is then sorted by descending count property.
Finally, the name is extracted from those objects with a map
, giving the resulting array of names.
Upvotes: 1
Reputation: 32216
The built in javascript .sort
method will be helpful here. You can pass it a comparator based on the name counts in your object.
So first create a map of name to number of occurrences, then an array of just the names themselves. Then the sort is pretty straightforward:
const myArray = [
{ testerId: '1',name:'Kaka'},
{ testerId: '3',name:'Messi'},
{ testerId: '3',name:'Messi'}, // 1 = 3 times (Kaka)
{ testerId: '3',name:'Messi'}, // 2 = 5 times (Ramos)
{ testerId: '3',name:'Messi'}, // 3 = 4 times (Messi)
{ testerId: '2',name:'Ramos'}, // 4 = 2 times (Neuer)
{ testerId: '2',name:'Ramos'}, // 5 = 6 times (Ronaldo)
{ testerId: '1',name:'Kaka'},
{ testerId: '5',name:'Ronaldo'},
{ testerId: '5',name:'Ronaldo'},
{ testerId: '5',name:'Ronaldo'},
{ testerId: '5',name:'Ronaldo'},
{ testerId: '5',name:'Ronaldo'},
{ testerId: '4',name:'Neuer'},
{ testerId: '4',name:'Neuer'},
{ testerId: '1',name:'Kaka'},
{ testerId: '2',name:'Ramos'},
{ testerId: '2',name:'Ramos'},
{ testerId: '2',name:'Ramos'},
{ testerId: '5',name:'Ronaldo'},
]
const myArrayCounts = myArray.reduce((counts, item) => {
if (counts[item.name] === undefined) counts[item.name] = 0;
counts[item.name]++;
return counts;
}, {});
const myArrayNames = myArray
.map(x => x.name)
.filter((x, i, l) => l.indexOf(x) === i); // Fancy deduplication filter
console.log(myArrayNames.sort((v1, v2) => {return myArrayCounts[v2] - myArrayCounts[v1]}))
Upvotes: 0
Reputation: 6872
I would solve this in 3 steps:
1) Count the # of occurrences for each element in the input.
2) Sort the # of occurrences in descending order.
3) Extract the name field
let input = [
{ testerId: '1',name:'Kaka'},
{ testerId: '3',name:'Messi'},
{ testerId: '3',name:'Messi'},
{ testerId: '3',name:'Messi'},
{ testerId: '3',name:'Messi'},
{ testerId: '2',name:'Ramos'},
{ testerId: '2',name:'Ramos'},
{ testerId: '1',name:'Kaka'},
{ testerId: '5',name:'Ronaldo'},
{ testerId: '5',name:'Ronaldo'},
{ testerId: '5',name:'Ronaldo'},
{ testerId: '5',name:'Ronaldo'},
{ testerId: '5',name:'Ronaldo'},
{ testerId: '4',name:'Neuer'},
{ testerId: '4',name:'Neuer'},
{ testerId: '1',name:'Kaka'},
{ testerId: '2',name:'Ramos'},
{ testerId: '2',name:'Ramos'},
{ testerId: '2',name:'Ramos'},
{ testerId: '5',name:'Ronaldo'},
];
//1)
let count = input.reduce((res, val) => {
if(res[val.name]) {
res[val.name]++;
} else {
res[val.name] = 1;
}
return res;
}, {});
let output = Object.entries(count)
.sort((a, b) => b[1]-a[1]) //2)
.map(v => v[0]); //3)
console.log(output);
Upvotes: 0
Reputation: 8670
You can use a set
object and a counter object to keep track of your entries. Then simply sort by the returned count.
let arr = [
{ testerId: '1',name:'Kaka'},
{ testerId: '3',name:'Messi'},
{ testerId: '3',name:'Messi'}, // 1 = 3 times (Kaka)
{ testerId: '3',name:'Messi'}, // 2 = 5 times (Ramos)
{ testerId: '3',name:'Messi'}, // 3 = 4 times (Messi)
{ testerId: '2',name:'Ramos'}, // 4 = 2 times (Neuer)
{ testerId: '2',name:'Ramos'}, // 5 = 6 times (Ronaldo)
{ testerId: '1',name:'Kaka'},
{ testerId: '5',name:'Ronaldo'},
{ testerId: '5',name:'Ronaldo'},
{ testerId: '5',name:'Ronaldo'},
{ testerId: '5',name:'Ronaldo'},
{ testerId: '5',name:'Ronaldo'},
{ testerId: '4',name:'Neuer'},
{ testerId: '4',name:'Neuer'},
{ testerId: '1',name:'Kaka'},
{ testerId: '2',name:'Ramos'},
{ testerId: '2',name:'Ramos'},
{ testerId: '2',name:'Ramos'},
{ testerId: '5',name:'Ronaldo'},
],
mySet = new Set(),
countObj = {};
for (let obj of arr) {
if (mySet.has(obj.name)) countObj[obj.name]++;
else {
countObj[obj.name] = 1;
mySet.add(obj.name);
}
}
arr = arr.sort(function(a, b) {
return (countObj[a.name] - countObj[b.name]);
});
console.log(arr);
Upvotes: 0