如何在javascript中统计数组中重复的值

183

目前,我有一个数组如下:

var uniqueCount = Array();

几步之后,我的数组看起来像这样:

uniqueCount = [a,b,c,d,d,e,a,b,c,f,g,h,h,h,e,a];
我该如何计算数组中有多少个a、b、c?我希望得到这样的结果:
a = 3
b = 1
c = 2
d = 2

1
可能是 https://dev59.com/DGnWa4cB1Zd3GeqPykA9 的重复问题。 - Vinay Pratap Singh Bhadauria
@Nirk 我猜musical_coder指的是{}这种类型的map,而不是函数式编程中的map - Matt Ball
35个回答

459

const counts = {};
const sampleArray = ['a', 'a', 'b', 'c'];
sampleArray.forEach(function (x) { counts[x] = (counts[x] || 0) + 1; });
console.log(counts)


15
这绝对是最简单的答案。 - Josh Beam
7
这个代码片段 (counts[x] || 0) + 1 是如何计数的呢? - jsduniya
8
表达式 counts[x] || 0 如果 counts[x] 已经被设置,则返回它的值;否则返回 0。通过加1并将其重新设置到对象中,计数就完成了。 - Constantinius
3
如果你在想为什么会有负评 - 那是我,我在手机上浏览时误点了按钮,没有注意到。等我发现时已经太晚无法更改。对此我感到抱歉,答案真的很好。如果你想编辑它,我很乐意撤销。 - Todor Minakov
12
同样使用 reduce 方法:var counts = your_array.reduce((map, val) => {map[val] = (map[val] || 0)+1; return map}, {} ); - Alberto89
显示剩余2条评论

96

类似这样:

uniqueCount = ["a","b","c","d","d","e","a","b","c","f","g","h","h","h","e","a"];
var count = {};
uniqueCount.forEach(function(i) { count[i] = (count[i]||0) + 1;});
console.log(count);

如果您不希望在旧的浏览器中发生错误,请使用简单的for循环代替forEach。


6
@web_dev创建了一个名为count的关联数组对象,其中将为数组中的每个唯一元素具有键值对,其中键是唯一元素的值,而值是计数。他遍历数组,并针对每个值递增该值或创建键值对(不存在键的值将求值为undefined,因此||运算符取零并添加1)。 - robisrob
1
@neelmeg 或许写出 "forEach" 的所有参数有助于更好地理解("i" 是每个数组值,而不是它的索引):uniqueCount.forEach(function(value, index) { count[value] = (count[value] || 0) + 1; }); - Pedro Ferreira
排序总计数量的一个好方法是什么? - tremor

79
我偶然发现了这个(非常老的)问题。有趣的是,最明显和优雅的解决方案(依我之见)被忽略了:Array.prototype.reduce(...)。自2011年(IE)或更早时起,所有主要浏览器都支持此功能。

var arr = ['a','b','c','d','d','e','a','b','c','f','g','h','h','h','e','a'];
var map = arr.reduce(function(prev, cur) {
  prev[cur] = (prev[cur] || 0) + 1;
  return prev;
}, {});

// map is an associative array mapping the elements to their frequency:
console.log(map);
// prints {"a": 3, "b": 2, "c": 2, "d": 2, "e": 2, "f": 1, "g": 1, "h": 3}

编辑:

使用箭头函数中的逗号操作符,我们可以将其写成一行代码:

var arr = ['a','b','c','d','d','e','a','b','c','f','g','h','h','h','e','a'];
var map = arr.reduce((cnt, cur) => (cnt[cur] = cnt[cur] + 1 || 1, cnt), {});

// map is an associative array mapping the elements to their frequency:
console.log(map);
// prints {"a": 3, "b": 2, "c": 2, "d": 2, "e": 2, "f": 1, "g": 1, "h": 3}

然而,由于这可能更难阅读/理解,因此应该坚持使用第一种版本。

有没有其他方法可以避免错误的参数重新赋值来完成这个操作? prev[cur] = (prev[cur] || 0) + 1; - keyboard-warrior
1
@keyboard-warrior 你说的“错误”是什么意思?这是完全合法的JS代码。它只是从0开始递增prev[cur]。(如果prev[0]未定义,则使用值0代替)。你也可以使用表达式(prev[cur] + 1) || 1,但这并没有太大区别。 - isnot2bad

36

function count() {
    array_elements = ["a", "b", "c", "d", "e", "a", "b", "c", "f", "g", "h", "h", "h", "e", "a"];

    array_elements.sort();

    var current = null;
    var cnt = 0;
    for (var i = 0; i < array_elements.length; i++) {
        if (array_elements[i] != current) {
            if (cnt > 0) {
                document.write(current + ' comes --> ' + cnt + ' times<br>');
            }
            current = array_elements[i];
            cnt = 1;
        } else {
            cnt++;
        }
    }
    if (cnt > 0) {
        document.write(current + ' comes --> ' + cnt + ' times');
    }

}

count();

演示Fiddle

你也可以使用高阶函数来执行操作。 查看这个答案


1
循环后面的额外if语句是不必要的...只需使用for (var i = 0; i <= array_elements.length; i++) {或者<=而不是<即可。 - heckascript
嗨@Vinay,也许你能在这里帮我吗?https://stackoverflow.com/questions/57819850/javascript-count-on-each-appearance-of-value-from-array-of-objects - SMPLYJR

30

简单就是美,一个变量,一个函数 :)

const arr = ["a", "b", "c", "d", "d", "e", "a", "b", "c", "f", "g", "h", "h", "h", "e", "a"];

const counts = arr.reduce((acc, value) => ({
   ...acc,
   [value]: (acc[value] || 0) + 1
}), {});

console.log(counts);


我知道这很老,但它看起来很简单。有人能向一个刚学会基本reduce用法的新手解释一下这里发生了什么吗? - Burton
1
当然,reduce允许您提供默认值(第二个参数),并通过reduce函数将其传递回来,以便您可以继续检查新值,“acc”(累积)将在我们循环遍历每个数组值时不断更新,在将其分配给对象后,我们可以检查它是否存在,并在迭代过程中将其值更新为1!希望这有所帮助 :) - Shannon Hochkins
把它改成 arr.sort().reduce((,你就得到了完美的解决方案!(但我还是给你点赞了) - undefined

11

// Initial array
let array = ['a', 'b', 'c', 'd', 'd', 'e', 'a', 'b', 'c', 'f', 'g', 'h', 'h', 'h', 'e', 'a'];

// Unique array without duplicates ['a', 'b', ... , 'h']
let unique = [...new Set(array)];

// This array counts duplicates [['a', 3], ['b', 2], ... , ['h', 3]] 
let duplicates = unique.map(value => [value, array.filter(str => str === value).length]);

11

使用reduce数组函数的单行代码

const uniqueCount =  ["a", "b", "c", "d", "d", "e", "a", "b", "c", "f", "g", "h", "h", "h", "e", "a"];
const distribution = uniqueCount.reduce((acum,cur) => Object.assign(acum,{[cur]: (acum[cur] || 0)+1}),{});
console.log(JSON.stringify(distribution,null,2));


我刚刚意识到@isnot2bad(https://dev59.com/XmIk5IYBdhLWcg3wTcnp#32886673)几乎和我的代码一样。我只是碰巧使用了箭头函数和常量。 - dinigo

10
似乎没有人在这里使用内置的Map(),而我通常会与Array.prototype.reduce()结合使用:

const data = ['a','b','c','d','d','e','a','b','c','f','g','h','h','h','e','a'];
const result = data.reduce((a, c) => a.set(c, (a.get(c) || 0) + 1), new Map());
console.log(...result);

注意,如果想在较旧的浏览器中使用它,您将需要使用polyfill库中的Map()


你能详细解释一下这是如何工作的吗?(特别是set/get部分) 我试图将reducer拆分为一个函数,但是我得到了“get不是一个函数”的响应。 - Antoine Nedelec
好的,getset函数来自于Map对象。但是初始累加器不是Map对象,那么为什么归约器的缩减版本需要一个呢? - Antoine Nedelec
@AntoineNedelec 初始值是一个新的 Map 对象;请参见 reduce 的第二个参数。Map.prototype.set 返回 map 对象,而 Map.prototype.get 返回 undefined 或提供给它的任何键的值。这使我们可以获取每个字母的当前计数(如果未定义,则为 0),然后将其增加一,然后将该字母的计数设置为新计数,这将返回 map 并成为新的累加器值。 - aendra

6

我认为这是在数组中计算相同值出现次数的最简单方法。

var a = [true, false, false, false];
a.filter(function(value){
    return value === false;
}).length                                      

这个问题是在询问如何在不指定值的情况下完成此操作。 - keyboard-warrior

5
使用 JavaScript 中的数组 reduce 方法非常简单:

const arr = ['a','d','r','a','a','f','d'];
const result =  arr.reduce((json,val)=>({...json, [val]:(json[val] | 0) + 1}),{});
console.log(result)
//{ a:3,d:2,r:1,f:1 }


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接