1

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.

3
  • 3
    What is your question? What have you tried? Commented Nov 27, 2017 at 21:36
  • my question is how to sort array of objects based on occurrence? Commented Nov 27, 2017 at 21:37
  • And, what have you tried? Because the output you have shown does not in any way correspond to the array you start with, except the object "name" key have the same elements. Do you want a function that makes a new array given an array of objects? Because then it seems like you should just count the number of objects and compare the counts. Commented Nov 27, 2017 at 21:39

4 Answers 4

1

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);

Explanation

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.

Sign up to request clarification or add additional context in comments.

3 Comments

functional !== hard to read... How is OP supposed to learn/understand when you omit almost all white-space? Is it relay necessary to botch it all up into a single blob?
@trincot, I will definitely try your solution as well. It''s really interesting.
@DhavalJardosh, I added a section with explanations. I hope it helps.
0

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);

3 Comments

It's not me. Actually I am trying your solution.
thank you very much! Your solution did help me as I was super stuck due to big data I am having.
Glad I could help!
0

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);

1 Comment

thank you very much! Your explanation is really useful.
0

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]}))

1 Comment

thank you very much! Your solution did help me as I was super stuck due to big data I am having.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.