在Javascript中找到众数的最简单方法

5

我是JavaScript的初学者,尝试编写寻找众数的代码。我的代码可以运行,但只能在连续输入时找到众数。当有这样一个数组a=[1,2,3,4,5,2]时,它无法找到众数。

由于我是初学者,不想写任何复杂的东西,希望以最简单的方式学习它。请问是否有人可以帮助我实现这个目的?

list = [1,2,3,4,5,6,7,7]
var empty = []
i = 0
max = 0
while (i<list.length){

   if (list[i]==list[i+1]){
       empty = list[i] 
   i += 1
    }else{
      i +=1
      }

 }
 document.write(empty) 


4
什么是众数(mode)? 众数是一组数据中出现次数最多的数值。 - Nina Scholz
2个回答

5
你的代码假设参数数组已经被预先排序,这是一个有风险和限制性的假设,只适用于排序后的数组(反例:[1,1,1,7,7] 错误地报告7 为众数)。
如果你希望继续使用这种方法,那么你正在走上正确的道路,但你需要跟踪当前/最佳连续值、当前/最佳元素,并在返回结果之前执行最长连续 streak 的最终检查。

var mode = a => {
  a = a.slice().sort((x, y) => x - y);

  var bestStreak = 1;
  var bestElem = a[0];
  var currentStreak = 1;
  var currentElem = a[0];

  for (let i = 1; i < a.length; i++) {
    if (a[i-1] !== a[i]) {
      if (currentStreak > bestStreak) {
        bestStreak = currentStreak;
        bestElem = currentElem;
      }

      currentStreak = 0;
      currentElem = a[i];
    }

    currentStreak++;
  }

  return currentStreak > bestStreak ? currentElem : bestElem;
};


console.log(mode([1,2,3,4,5,6,7,7]));
console.log(mode([1,1,1,4,5,6,7,7]));
console.log(mode([1,2,3,3,3,6,3,7]));
console.log(mode([1,3,3,4,5,2,2,1]));
console.log(mode([]));

话虽如此,排序是一种非线性操作,因此我建议尝试另一种方法。

这个想法是使用对象来记录数组中每个项目的出现次数,然后取出出现次数最高的元素。我使用reduce执行这两个操作:

const mode = a => 
  Object.values(
    a.reduce((count, e) => {
      if (!(e in count)) {
        count[e] = [0, e];
      }
      
      count[e][0]++;
      return count;
    }, {})
  ).reduce((a, v) => v[0] < a[0] ? a : v, [0, null])[1];
;

console.log(mode([1,2,3,4,5,6,7,7]));
console.log(mode([1,1,1,4,5,6,7,7]));
console.log(mode([1,2,3,3,3,6,3,7]));
console.log(mode([1,3,3,4,5,2,2,1]));
console.log(mode([]));

或者,同样的事情,为了易读性而不使用reduce编写:

const mode = a => {
  const count = {};
  
  a.forEach(e => {
    if (!(e in count)) {
      count[e] = 0;
    }

    count[e]++;
  });

  let bestElement;
  let bestCount = 0;

  Object.entries(count).forEach(([k, v]) => {
    if (v > bestCount) {
      bestElement = k;
      bestCount = v;
    }
  });
  
  return bestElement;
};

console.log(mode([1,2,3,4,5,6,7,7]));
console.log(mode([1,1,1,4,5,6,7,7]));
console.log(mode([1,2,3,3,3,6,3,7]));
console.log(mode([1,3,3,4,5,2,2,1]));
console.log(mode([]));

请注意,这些方法在遇到并列情况时不会选择相同的模式。您可能希望添加一个数组来跟踪所有模式,或更改算法以选择第一个或最后一个出现的模式以满足您的需求。

一个小问题是,没有捕获到当没有找到模式实例的情况。如果没有找到模式,则该函数返回数组中的最后一个数字。 - tcanbolat
2
所有(非空)数组都有一种模式。如果所有元素的频率相同,我将其解释为可以返回其中任何一个。 - ggorlen

3
使用哈希表。
list = [1,2,3,4,5,6,7,7]
counts = {}
list.forEach(function(e) {
  if(counts[e] === undefined) {
    counts[e] = 0
  }
  counts[e] += 1
})

这将导致以下结果:

{1:1,2:1,3:1,4:1,5:1,6:1,7:2}

这个相关问题涉及在哈希表中查找最大值和最小值,这本质上就是你在最后所做的。

快速获取对象属性中的最小/最大值的方法


1
在统计学中,众数不是指出现的次数,而是指出现次数最多的数字。因此,我们要寻找的是一个键而不是一个值。你的解决方案很好地找到了这个值,但没有找到相关的键。 - Banane
感谢您的见解。拥有多种选择技术总是很好的。 - Erik Rybalkin

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