I have an array of objects,
const myArray = [{id:1, k_id:1},{id:2, k_id:2},{id:3, k_id:1},{id:4, k_id:3},{id:5, k_id:3},{id:6, k_id:2},{id:7, k_id:2},{id:8, k_id:4}];
myArray.sort((a, b) => a.k_id - b.k_id);
console.log(myArray);
I want it to be sorted based on the k_id and it occurrences(descending frequency). But, have to keep all the elements as I have other values in the objects. Other key, value pairs can be in any order. (I have simplified my issue here with only two key, value pairs but the actual array have more than 15 key, value pairs)
Output Produced:
(8) [{id:1,k_id:1},{id:3,k_id:1},{id:2,k_id:2},{id:6,k_id:2},{id:7,k_id:2},{id:4,k_id:3},{id:5,k_id:3},{id:8,k_id:4}]
Expected output, because I need them to be sorted like below as k_id:2 occured more than k_id:1:
myArray = [{id:6, k_id:2},{id:7, k_id:2},{id:2, k_id:2},{id:3, k_id:1},{id:1, k_id:1},{id:4, k_id:3},{id:5, k_id:3},{id:8, k_id:4}];
try this out, I'm not sure if it would scale but, it works fine.
const myArray = [{id:1, k_id:1},{id:2, k_id:2},{id:3, k_id:1},{id:4, k_id:3},{id:5, k_id:3},{id:6, k_id:2},{id:7, k_id:2},{id:8, k_id:4}];
(()=>{
const keys = {}
const newArray = [];
/**
* Determenin every keys count
*/
for(const one of myArray){
// if the key is not yet registered in keys
// initialize 0 and add one either way
// on the key count
keys[one.k_id] = (keys[one.k_id] || 0) + 1;
}
console.log(keys)
//
function GetTheHighestFrequency () {
/**
* @return {object} highest
*
* containing a key or K_id
* and its frequency count
*/
let highest = { key:0,frequency:0 };
for(const [key,value] of Object.entries(keys)){
if(value > highest.frequency)
highest = { key,frequency:value };
}
return highest
}
//
// return new array
for(const each of Object.keys(keys)){
// request the highest frequency key K_id
const highest = GetTheHighestFrequency();
//
// Add (Push) objects in the newArray
//
for(const one of myArray){
// add an object if
// if the K_id matches the current
// highest key value
if(String(one.k_id) === highest.key)
newArray.push(one)
}
delete keys[highest.key]
}
console.log("the result is = ",newArray)
})()
Looking for something like this?
inp.sort((a, b) =>
inp.filter(c => c.k_id === b.k_id).length -
inp.filter(c => c.k_id === a.k_id).length
);
// sorting a vs b by counting the occurency of each k_id property value
// using filter
const inp = [{id:1, k_id:1},{id:2, k_id:2},{id:3, k_id:1},{id:4, k_id:3},{id:5, k_id:3},{id:6, k_id:2},{id:7, k_id:2},{id:8, k_id:4}];
console.log(
inp.sort((a, b) => inp.filter(c => c.k_id === b.k_id).length - inp.filter(c => c.k_id === a.k_id).length)
)
I would suggest first creating a frequency lookup. Below I've used reduce with a Map, but you can use a regular object and a for loop to build the same look up. The Map has keys which are the k_id, and the value of each k_id is the number of times k_id occurs. Creating the lookup means you don't need to loop through your array each iteration of your sort. You can then use .sort() and sort by the occurrences for each key_id stored within the frequency map. As this uses .sort(), the sort is stable, so items with the same k_id will keep their relative ordering from the original array:
const myArray = [{id:1, k_id:1},{id:2, k_id:2},{id:3, k_id:1},{id:4, k_id:3},{id:5, k_id:3},{id:6, k_id:2},{id:7, k_id:2},{id:8, k_id:4}];
const freq = myArray.reduce((acc, {k_id}) => acc.set(k_id, (acc.get(k_id) || 0) + 1), new Map);
myArray.sort((a, b) => freq.get(b.k_id) - freq.get(a.k_id));
console.log(myArray);