【问题标题】:Count number occurences in array and sorting them计算数组中出现的次数并对其进行排序
【发布时间】:2021-12-17 06:16:51
【问题描述】:

我想在数组中查找数字的出现,然后显示数字和出现的数字,这些数字按升序排序,如下所示:

let arr = [9,-10,2,9,6,1,2,10,-8,-10,2,9,6,1];

// {'-10': 2, '-8': 1, '1': 2, '2': 3, '6': 2, '9': 3, '10': 1}

我通过将数组中的每个数字存储在一个对象中来找到它们的出现次数。当我尝试使用console.log numCount 时,除负数外,所有数字均按升序排序。

/*Find occurrences*/
let numCount = {};
for(let num of arr){
    numCount[num] = numCount[num] ? numCount[num] + 1 : 1;
}
console.log(numCount);
//{ '1': 2, '2': 3, '6': 2, '9': 3, '10': 1, '-10': 2, '-8': 1 }

我查找了如何对对象进行排序,看起来这样做的方法是将它们存储在一个数组中,然后对其进行排序。所以这就是我尝试过的:

/*Store them in array and then sort it*/
let sortedArray = [];
for(let item in numCount){
    sortedArray.push([item, numCount[item]]);
}
sortedArray.sort(function(a,b){
    return a[0] - b[0];
});

/*
console.log(sortedArray);
[
  [ '-10', 2 ],
  [ '-8', 1 ],
  [ '1', 2 ],
  [ '2', 3 ],
  [ '6', 2 ],
  [ '9', 3 ],
  [ '10', 1 ]
]
*/

下一个方法应该将它们显示在按升序排序的对象中,但是当我尝试它时,它在该对象的末尾以负数显示它们,就像在开始时一样。所以这是我卡住的部分。

let sortedObject = {};
sortedArray.forEach(function(item){
    sortedObject[item[0]] = item[1];
})
/*console.log(sortedObject);
{ '1': 2, '2': 3, '6': 2, '9': 3, '10': 1, '-10': 2, '-8': 1 }
*/

完整代码:

let arr = [9,-10,2,9,6,1,2,10,-8,-10,2,9,6,1];

/*Find occurrences*/
let numCount = {};
for(let num of arr){
    numCount[num] = numCount[num] ? numCount[num] + 1 : 1;
}

/*Store them in array and then sort it*/
let sortedArray = [];
for(let item in numCount){
    sortedArray.push([item, numCount[item]]);
}
sortedArray.sort(function(a,b){
    return a[0] - b[0];
});


let sortedObject = {};
sortedArray.forEach(function(item){
    sortedObject[item[0]] = item[1];
})

console.log(sortedObject);

【问题讨论】:

  • 对象属性未排序。这是愚蠢的差事。
  • 为什么你需要它成为一个对象,而不是(例如)你的 sortedArray?
  • 我想这里的问题是键(或至少其中一些)被认为是整数,你不能改变顺序。

标签: javascript arrays sorting object


【解决方案1】:

Map 可能允许您对对象执行您想要执行的操作,同时允许您设置关键顺序。

let arr = [9,-10,2,9,6,1,2,10,-8,-10,2,9,6,1];

/*Find occurrences*/
let numCount = new Map();
for(let num of arr){
  numCount.set(num, (numCount.get(num) ?? 0) + 1);
}

let sortedMap = new Map([...numCount.entries()].sort((a, b) => a[0] - b[0]));

console.log(sortedMap.get(-10));
console.log(...sortedMap.keys());
console.log(...sortedMap.values());

【讨论】:

    【解决方案2】:

    对象属性的排序不可靠,对象的显示方式取决于console.log 的特定实现。

    如果,奇怪的是,它 只是一个显示问题,那么你可以使用,例如

    const sortedArray = [[-10, 2], [-8, 1], [1, 2], [2, 3], [6, 2], [9, 3], [10, 1]];
    
    let result = `{${sortedArray.map(el => `'${el[0]}': ${el[1]}`).join(', ')}}`;
    
    console.log(result);

    【讨论】:

      【解决方案3】:

      关于属性/键如何在对象中排序有一些规则,如果您了解这些规则,它们会可靠地排序

      如果属性是类似正数的(实际上所有属性都是字符串,即使它们看起来像数字),它将被排序加入。如果不是,它将按插入顺序排序。但是 object 是如何判断一个属性值是不是 number-like 的呢?

      考虑键 '9' :首先将其转换为数字 9。因为它是正数,所以将其转换回字符串 '9'。与第一个值相同。所以它被认为是正数状的正数状。

      考虑键 '-10' :首先将其转换为 -10 的数字。

      因为它不是正数,所以它被认为是一个字符串......其余的都是一样的。

      所以现在很明显,对类似正数的属性进行排序根本没有必要。输入数组是否排序,结果相同,顺序由规则决定。

      解决方案:

      考虑键 '09' :首先将其转换为数字 9。因为它是正数,所以将其转换回字符串 '9'。与第一个值不同。所以它被认为是一个字符串。

      所以让我们在每个正数前加一个“0”,然后在排序后将其转换为字符串。

      sortedArray.forEach(function(item){
          let key = parseInt(item[0])>0 ? '0'+item[0] : item[0]
          sortedObject[key] = item[1];
      })
      //{ "-10": 2, "-8": 1, 01: 2, 02: 3, 06: 2, 09: 3, 010: 1 }
      

      请注意,对于 010 这样的数字,parseInt 的行为是不同的,因为它假定它们是八进制的。

      另一个更好的解决方案是使用地图,阅读更多关于地图及其与对象的区别here

      【讨论】:

      • "结论:即使在 ES2015 中你也不应该依赖 JavaScript 中普通对象的属性顺序,这样容易出错。" - T. J. Crowder.
      猜你喜欢
      • 1970-01-01
      • 2016-10-06
      • 1970-01-01
      • 1970-01-01
      • 2012-08-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多