在Javascript中,我试图采取数字值的初始数组,并计算其中的元素。理想情况下,结果将是两个新数组,第一个数组指定每个唯一元素,第二个数组包含每个元素出现的次数。但是,我愿意听取关于输出格式的建议。

例如,如果初始数组是:

5, 5, 5, 2, 2, 2, 2, 2, 9, 4

然后将创建两个新数组。第一个将包含每个唯一元素的名称:

5, 2, 9, 4

第二个将包含该元素在初始数组中出现的次数:

3, 5, 1, 1

因为数字5在初始数组中出现了三次,数字2出现了五次,9和4都出现了一次。

我一直在寻找解决方案,但似乎没有一个可行,而且我自己尝试过的每件事最后都出奇地复杂。任何帮助都将不胜感激!

谢谢:)


当前回答

如果你使用下划线,你可以走功能路线

a = ['foo', 'foo', 'bar'];

var results = _.reduce(a,function(counts,key){ counts[key]++; return counts },
                  _.object( _.map( _.uniq(a), function(key) { return [key, 0] })))

第一个数组是

_.keys(results)

第二个数组是

_.values(results)

如果本地javascript函数可用,其中大部分将默认为本地javascript函数

演示:http://jsfiddle.net/dAaUU/

其他回答

使用ramda.js有一个更好更简单的方法可以做到这一点。 代码示例

Const ary = [5,5,5,2,2,2,2,2,2,2,2,2,9,4]; R.countBy (r = > r)(必要) countBy documentation是at documentation

2021年的版本

更优雅的方法是使用逻辑空赋值(x ??= y)结合数组#reduce()与O(n)时间复杂度。

主要思想仍然是使用array# reduce()将输出作为对象进行聚合,以获得最高的性能(时间和空间复杂度),就像其他答案一样,搜索和构造中间数组。

Const arr = [2,2,2,2,2,2,4,5,5,5,9]; Const result = arr。Reduce ((acc, curr) => { acc(咕咕叫)? ?= {[curr]: 0}; acc[咕咕叫][咕咕叫]+ +; 返回acc; }, {}); console.log (Object.values(结果));

清理和重构代码

使用逗号操作符(,)语法。

逗号操作符(,)计算它的每个操作数(从左到右) 右)并返回最后一个操作数的值。

Const arr = [2,2,2,2,2,2,4,5,5,5,9]; Const result = arr。减少((acc,咕咕叫)= > (acc[咕咕叫]= (acc(咕咕叫)| | 0)+ 1,acc), {}); console.log(结果);

输出

{
  "2": 5,
  "4": 1,
  "5": 3,
  "9": 1
}

如果使用下划线或lodash,这是最简单的事情:

_.countBy(array);

这样:

_.countBy([5, 5, 5, 2, 2, 2, 2, 2, 9, 4])
=> Object {2: 5, 4: 1, 5: 3, 9: 1}

正如其他人指出的那样,然后可以对结果执行_.keys()和_.values()函数,以分别获得唯一的数字及其出现次数。但根据我的经验,原始对象更容易处理。

这个问题已经有8年的历史了,很多很多的答案都没有考虑到ES6及其众多的优势。

也许更重要的是,当我们创建额外的数组,创建数组的两倍或三倍副本,甚至将数组转换为对象时,考虑我们的代码对垃圾收集/内存管理的后果。对于小型应用来说,这些都是微不足道的观察结果,但如果规模化是一个长期目标,那么就要彻底考虑这些问题。

如果您只是需要一个特定数据类型的“计数器”,并且起点是一个数组(我假设您因此想要一个有序列表,并利用数组提供的许多属性和方法),那么您只需简单地遍历array1,并用array1中找到的这些值的值和出现次数填充array2。

就这么简单。

面向对象编程和面向对象设计的简单类SimpleCounter (ES6)的示例

class SimpleCounter { 

    constructor(rawList){ // input array type
        this.rawList = rawList;
        this.finalList = [];
    }

    mapValues(){ // returns a new array

        this.rawList.forEach(value => {
            this.finalList[value] ? this.finalList[value]++ : this.finalList[value] = 1;
        });

        this.rawList = null; // remove array1 for garbage collection

        return this.finalList;

    }

}

module.exports = SimpleCounter;

您可以通过使用count函数扩展数组来简化这一点。它的工作原理类似于Ruby的array# count,如果你熟悉它的话。

Array.prototype.count = function(obj){
  var count = this.length;
  if(typeof(obj) !== "undefined"){
    var array = this.slice(0), count = 0; // clone array and reset count
    for(i = 0; i < array.length; i++){
      if(array[i] == obj){ count++ }
    }
  }
  return count;
}

用法:

let array = ['a', 'b', 'd', 'a', 'c'];
array.count('a'); // => 2
array.count('b'); // => 1
array.count('e'); // => 0
array.count(); // => 5

Gist


Edit

然后你可以使用array# filter获取你的第一个数组,包含每个出现的项:

let occurred = [];
array.filter(function(item) {
  if (!occurred.includes(item)) {
    occurred.push(item);
    return true;
  }
}); // => ["a", "b", "d", "c"]

你的第二个数组,使用数组#count到数组#map:

occurred.map(array.count.bind(array)); // => [2, 1, 1, 1]

或者,如果顺序无关紧要,你可以直接返回一个键值对:

let occurrences = {}
occurred.forEach(function(item) { occurrences[item] = array.count(item) });
occurences; // => {2: 5, 4: 1, 5: 3, 9: 1}