我正在寻找一种优雅的方法来确定JavaScript 数组中哪个元素出现次数最多(mode)。
例如,在
['pear', 'apple', 'orange', 'apple']
'apple'
元素是最常见的元素。
我正在寻找一种优雅的方法来确定JavaScript 数组中哪个元素出现次数最多(mode)。
例如,在
['pear', 'apple', 'orange', 'apple']
'apple'
元素是最常见的元素。
这只是模式。这是一个快速的、非优化的解决方案。它应该是 O(n)。
function mode(array)
{
if(array.length == 0)
return null;
var modeMap = {};
var maxEl = array[0], maxCount = 1;
for(var i = 0; i < array.length; i++)
{
var el = array[i];
if(modeMap[el] == null)
modeMap[el] = 1;
else
modeMap[el]++;
if(modeMap[el] > maxCount)
{
maxEl = el;
maxCount = modeMap[el];
}
}
return maxEl;
}
自 2009 年以来,javascript 有了一些发展——我想我会添加另一个选项。我不太关心效率,直到它实际上是一个问题,所以我对“优雅”代码的定义(如 OP 所规定的)有利于可读性——这当然是主观的......
function mode(arr){
return arr.sort((a,b) =>
arr.filter(v => v===a).length
- arr.filter(v => v===b).length
).pop();
}
mode(['pear', 'apple', 'orange', 'apple']); // apple
在此特定示例中,如果集合中的两个或多个元素出现相同的次数,则将返回数组中出现最晚的那个。还值得指出的是,它会修改您的原始数组 - 如果您希望Array.slice
事先调用,可以防止这种情况发生 。
编辑:用一些ES6 粗 箭头更新了示例,因为2015 年发生了,我认为它们看起来很漂亮……如果您关心向后兼容性,您可以在修订历史记录中找到它。
根据George Jempty's
让算法说明关系的请求,我提出了Matthew Flaschen's
算法的修改版本。
function modeString(array) {
if (array.length == 0) return null;
var modeMap = {},
maxEl = array[0],
maxCount = 1;
for (var i = 0; i < array.length; i++) {
var el = array[i];
if (modeMap[el] == null) modeMap[el] = 1;
else modeMap[el]++;
if (modeMap[el] > maxCount) {
maxEl = el;
maxCount = modeMap[el];
} else if (modeMap[el] == maxCount) {
maxEl += "&" + el;
maxCount = modeMap[el];
}
}
return maxEl;
}
现在将返回一个字符串,其中模式元素由&
符号分隔。收到结果后,它可以在该&
元素上拆分,并且您拥有自己的模式。
另一种选择是返回一组模式元素,如下所示:
function modeArray(array) {
if (array.length == 0) return null;
var modeMap = {},
maxCount = 1,
modes = [];
for (var i = 0; i < array.length; i++) {
var el = array[i];
if (modeMap[el] == null) modeMap[el] = 1;
else modeMap[el]++;
if (modeMap[el] > maxCount) {
modes = [el];
maxCount = modeMap[el];
} else if (modeMap[el] == maxCount) {
modes.push(el);
maxCount = modeMap[el];
}
}
return modes;
}
在上面的示例中,您将能够将函数的结果作为模式数组进行处理。
根据Emissary的 ES6+ 答案,您可以Array.prototype.reduce
用来进行比较(而不是排序、弹出和可能改变您的数组),我认为这看起来很巧妙。
const mode = (myArray) =>
myArray.reduce(
(a,b,i,arr)=>
(arr.filter(v=>v===a).length>=arr.filter(v=>v===b).length?a:b),
null)
我默认为 null,如果 null 是您要过滤的可能选项,则它不会总是给您真实的响应,也许这可能是可选的第二个参数
与其他各种解决方案一样,它的缺点是它不处理“绘制状态”,但这仍然可以通过稍微复杂的减少功能来实现。
a=['pear', 'apple', 'orange', 'apple'];
b={};
max='', maxi=0;
for(let k of a) {
if(b[k]) b[k]++; else b[k]=1;
if(maxi < b[k]) { max=k; maxi=b[k] }
}