【问题标题】:Sort an array of objects based on frequency but keep repeated elements根据频率对对象数组进行排序,但保留重复元素
【发布时间】:2022-02-02 21:57:24
【问题描述】:

我有一个对象数组,

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

我希望它根据 k_id 及其出现次数(降频)进行排序。但是,必须保留所有元素,因为我在对象中有其他值。其他键、值对可以按任何顺序排列。 (我在这里简化了我的问题,只有两个键值对,但实际数组有超过 15 个键值对)

产生的输出:

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

预期的输出,因为我需要将它们排序如下,因为k_id:2 出现的次数多于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}];

【问题讨论】:

  • 在发布问题之前请阅读How to Askminimal reproducible example
  • @zer00ne 更新了问题
  • 输出的例子没有意义。 k_id 值的顺序如下:2,...2,..1,...1,...3,...3,...4 ?
  • 为什么是{id:6, k_id:2},{id:7, k_id:2},{id:2, k_id:2}而不是{id:2, k_id:2}, {id:6, k_id:2},{id:7, k_id:2},因为这里的项目会保持它们的相对顺序,还是没关系?
  • @NickParsons 没关系。只是 k_id 应该在它的出现次数中排序。 id 和其他键值对可以是任意顺序

标签: javascript arrays sorting object key-value


【解决方案1】:

寻找这样的东西?

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

【讨论】:

    【解决方案2】:

    试试这个,我不确定它是否会扩展,但它工作正常。

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

    【讨论】:

      【解决方案3】:

      我建议首先创建频率查找。下面我使用了reduceMap,但是您可以使用常规对象和for 循环来构建相同的查找。 Map 的键是k_id,每个k_id 的值是k_id 出现的次数。创建查找意味着您不需要在排序的每次迭代中循环遍历您的数组。然后,您可以使用.sort() 并按存储在频率图中的每个key_id 的出现次数进行排序。由于这使用了.sort(),因此排序为stable,因此具有相同k_id 的项目将保持它们与原始数组的相对顺序:

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

      【讨论】:

      • 为什么是 dv?如果我的回答有问题或者我误解了问题,请指出,我会尽力解决。
      最近更新 更多