JavaScript 数组中如何计算重复元素

3
请考虑这个JS函数。
我看到了类似的问题,但是无法理解。
function a (ResultArray){
    var counts={};
    for ( p = 0; p < ResultArray.length; p++){            
        counts[ResultArray[p]] = (counts[ResultArray[p]] + 1) || 1;            
    }
    return counts;
}

var arr = ["a","b","c","d","a","b","e"];        
var res = new a(arr);
console.log(res)

它正常工作并给出计数。我需要了解它如何给出计数,特别是(counts[ResultArray[p]] + 1) || 1;部分。 +1||的作用是什么。


2
看起来它试图递增特定键的值,然后如果失败(因为该键不存在),则将其设置为1。说实话,这是一行非常奇怪的代码。 - byxor
4
+1 表示将 1 加到 counts[ResultArray[p]] 中,|| 是真值检查:如果 counts[ResultArray[p]] + 1NaN、undefined、null 或 0,则表达式将求值为 1。详情请参见 此处 的帖子。 - Patrick Barr
@Patrick Barr,这就是我想要理解的,通过加1它实现了什么,或者通过加1它检查了什么。它是在检查下一个值吗?如果是的话,那么它是如何跟踪以前找到的值并递增它们的。对我来说太混乱了。 - user1207289
array.length - (new Set(array)).length 也可以。 - Jonas Wilms
1
@user1207289 它通过一个对象来跟踪数组中某个元素出现的次数,该对象的键是数组中的值,因此它只需将该值的计数加1,最后该对象将包含每个重复元素的计数。 - Patrick Barr
3个回答

3
我猜主要的困惑来自于这句话:

我猜主要的困惑来自于这句话:

counts[ResultArray[p]] = (counts[ResultArray[p]] + 1) || 1;
|| 运算符返回左侧的内容,如果它是“真值”(除了“假值”false0''nullundefinedNaN之外的任何值),否则返回右侧内容。
如果 ResultArray[p] 不在 counts 中,则 counts[ResultArray[p]] 将为 undefined。由于 undefined + 1NaN,所以 || 的左侧是“假值”,因此它将返回右侧的 1
否则,counts[ResultArray[p]] 将是我们已经看到 ResultArray[p] 的次数,并且我们将其加上 1。在这种情况下,左侧将是“真值”,它将返回新的计数。

我更加困惑了,1)为什么counts [ResultArray [p]]是次数而不是“a”,当这个var counts = {}; counts ["a"] = 1; counts ["b"] = 2; console.log(counts ["a"]);打印出1。2)假设我理解了问题1中的问题,当ResultArray [p]不在counts中并且返回1时,这是否意味着它增加了1或该迭代未被计算? - user1207289
请忽略上面的1),我理解counts [ResultArray [p]]是值为“a”而不是“a”。 - user1207289
1
假设 ResultArray[p]"a", 且 "a" 不在 counts 中。那么 counts[ResultArray[p]] = (counts[ResultArray[p]] + 1) || 1 就等同于 counts["a"] = (counts["a"] + 1) || 1,这又等同于 counts["a"] = (undefined + 1) || 1,再等同于 counts["a"] = NaN || 1,最终就等同于 counts["a"] = 1。也就是说,第一次遇到 "a" 时,我们将 counts["a"] 设为 1 - Peter Olson
我认为这样阅读可以更好地理解,只是在这里分享一下,以防有人需要。当遇到一个元素时,特定的行将被评估为 key 的值 = (key 的先前值 +1) || 1,由于每个键值在第一次遇到键时都是 undefined,所以该行将被评估为 key 的值 = (undefined +1) || 1 - user1207289

1
数组值尚未设置,因此无法对未定义的值进行递增。第一次遇到一个值时,“|| 1”部分将初始值设置为1。如果再次遇到相同的索引(不再是未定义的,而是已设置为1),则执行左侧并将现有值增加1。

当我现在阅读这个答案,在上面的解释之后,它有意义了。 - user1207289

0

在上述算法中,有一些需要牢记的事情。

  1. JavaScript对象由集合和字典表示,因此counts = {}只是一个集合或字典,因此可以使用counts."a"counts.acounts[a]来访问counts对象中的值,因此counts.a = 1counts["a"] = null是对计数集合(对象)进行的赋值操作。
  2. JavaScript动态分配变量,因此counts[ResultArray[p]] sincecountsis a object javascript dynamically creates the value of ResultArray[p]]as a property or key tocounts` as javascript is loosely typed
  3. 评估从行counts[ResultArray[p]] = (counts[ResultArray[p]] + 1) || 1;的左侧开始。JavaScript从count[ResultArray[p]]开始评估,其中counts评估为一个对象(集合、字典),然后移动到ResultArray,在运行时评估为数组,然后p被评估为一个数字,比如第一次迭代中的0,因此整个评估过程是counts[ResultArray[0]],其中JavaScript创建了键counts.acounts."a"并将其分配给未定义的评估,然后继续执行(counts[ResultArray[p]] + 1) || 1; 在其中counts[ResultArray[p]]已经在前一步中完成了评估,它评估为counts.acounts."a"=未定义,然后移动到undefined +,这应该在左右评估之后看起来像这样:(undefined + 1),然后JavaScript将其评估为NaN在下一个评估步骤中
    '(NaN)|| 1 whereNaN在JavaScript中始终为false,但1在JavaScript中始终为true,true = 1 false = 0,因此1被分配给counts.acounts."a"或counts[a] = 1

这里是从左到右分解的JavaScript评估步骤 counts[ResultArray[p]] = (counts[ResultArray[p]] + 1) || 1;

  1. counts = {}(对象,集合或字典)在JavaScript中
  2. ResultArray(数组)
  3. p(整数)
  4. 在第一次迭代中,ResultArray[p] = "a"
  5. counts["a"](未定义,因为之前没有分配)
  6. =(赋值运算符)
  7. counts = {}(对象,集合或字典)在JavaScript中
  8. ResultArray(数组)
  9. p(整数)
  10. 在第一次迭代中,ResultArray[p] = "a"
  11. counts["a"](未定义)
  12. +(加法运算)
  13. 1(整数)
  14. counts["a"] + 1 = undefined + 1 = NaN
  15. NaN || 1 = 1(布尔值1 = true false = 0 Nan = 0 = false 0 || 1 1在or语句中胜出)
  16. counts["a"] = 0 || 1(1被分配给counts["a"])

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