0

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}];
Nick Parsons
  • 45,728
  • 6
  • 46
  • 64
Fasna
  • 564
  • 1
  • 10
  • 28
  • 1
    Please read [ask] and [mcve] before posting a question. – zer00ne Feb 02 '22 at 12:38
  • The example of the output doesn't make sense. The `k_id` values are in this order: 2,...2,..1,...1,...3,...3,...4 ? – zer00ne Feb 02 '22 at 12:49
  • Why is it `{id:6, k_id:2},{id:7, k_id:2},{id:2, k_id:2}` and not `{id:2, k_id:2}, {id:6, k_id:2},{id:7, k_id:2}`, as items here will keep their relative orderings, or does it not matter? – Nick Parsons Feb 02 '22 at 12:52
  • @NickParsons it doesn't matter. just the k_id shoud be ordered in the count of it's occurences. id and other key-value pairs can be in any order – Fasna Feb 02 '22 at 12:54
  • @zer00ne It's 2,...2,...2,..1,...1,...3,...3,...4 – Fasna Feb 02 '22 at 12:54

3 Answers3

1

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)
)
stacj
  • 1,103
  • 1
  • 7
  • 20
1

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)
})()
0

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);
Nick Parsons
  • 45,728
  • 6
  • 46
  • 64
  • Why the dv? If something is wrong with my answer or if I've misunderstood the question please point it out and I will try and fix it. – Nick Parsons Feb 02 '22 at 22:26