我正在尝试获取数组中最常出现的数字,因此对于包含1,2,10,5,1的数组,结果应为1.我写的代码返回的频率为每个数字,所以1发生两次,2发生一次,10发生一次等任何建议如何我可以修复我的结果?
function mode(arr) {
var uniqNum = {};
var numCounter = function(num, counter) {
if(!uniqNum.hasOwnProperty(num)) {
uniqNum[num] = 1;
} else {
uniqNum[num] ++;
}
};
arr.forEach(numCounter);
return uniqNum;
}
答案 0 :(得分:1)
首先,我们要创建一个数组,用于计算特定值到此时的出现次数。
然后我们使用reduce函数返回从原始数组中读取的值的数组,以获取其值具有当前最大外观的索引。我们重新定义最大值并清空模式的最终输出数组(如果建立了新的最大值)。我们希望这是一个集合,以防万一出现最大限度的外观。
以下的其他优点是它不需要更昂贵的排序o(nlog n)并且将时间复杂度保持为线性。我还希望将所使用的功能仅保留为两个(map和reduce),因为在这种情况下只需要它。
编辑:修复了一个主要错误uniqNum [e] + = 1而不是uniqNum [e] + 1因为我的初始案例数组仍然返回预期结果而被忽视。还使语法更简洁,有利于更多评论。
var arr = [1,2,10,5,1,5,2,2,5,3,3];
//global max to keep track of which value has most appearances.
var max = -1;
var uniqNum = {};
var modeArray = arr.map(function(e) {
//create array that counts appearances of the value up to that point starting from beginning of the input arr array.
if(!uniqNum.hasOwnProperty(e)) {
uniqNum[e] = 1;
return 1;
} else {
return uniqNum[e] += 1;
}
//reduce the above appearance count array into an array that only contains values of the modes
}).reduce(function (modes, e1, i) {
//if max gets beaten then redefine the mode array to only include the new max appearance value.
if(e1 > max){
//redefining max
max = e1;
//returning only the new max element
return [arr[i]];
//if its a tie we still want to include the current value but we don't want to empty the array.
}else if(e1 == max){
//append onto the modes array the co-max value
return[...modes, arr[i]];
}
return modes;
},[]);
alert(modeArray);

这是一个测试,你可以运行我对@acontell的解决方案。在我的浏览器(Chrome with V8)中,我的解决方案对于具有大量重复值的阵列来说快了大约四到四倍,对于具有较少重复值的分布来说甚至更大的优势。 @acontell' s确实是一个更清洁的解决方案,但绝对不会更快执行。
var arr = [];
for(var i=0; i < 100000; i++){
arr.push(Math.floor(Math.random() * (100 - 1)) + 1);
}
console.time("test");
test();
function test(){
var max = -1;
var uniqNum = {};
var modeArray = arr.map(function(e) {
//create array that counts appearances of the value up to that point starting from beginning of the input arr array.
if(!uniqNum.hasOwnProperty(e)) {
uniqNum[e] = 1;
return 1;
} else {
return uniqNum[e] += 1;
}
//reduce the above appearance count array into an array that only contains values of the modes
}).reduce(function (modes, e1, i) {
//if max gets beaten then redefine the mode array to only include the new max appearance value.
if(e1 > max){
//redefining max
max = e1;
//returning only the new max element
return [arr[i]];
//if its a tie we still want to include the current value but we don't want to empty the array.
}else if(e1 == max){
//append onto the modes array the co-max value
modes.push(arr[i])
return modes;
}
return modes;
},[]);
}
console.timeEnd("test");
console.time("test1");
test1();
function test1 () {
var freq = [],
uniqNum = {},
i;
arr.forEach(function(num) {
uniqNum[num] = i = (uniqNum[num] || 0) + 1;
freq[i] = (freq[i] || []).concat(num);
});
return freq[freq.length - 1];
}
console.timeEnd("test1");
&#13;
答案 1 :(得分:1)
我保持你的代码不变,并添加了一些额外的声明。以下是演示:http://codepen.io/PiotrBerebecki/pen/rrdxRo
function mode(arr) {
var uniqNum = {};
var numCounter = function(num, counter) {
if(!uniqNum.hasOwnProperty(num)) {
uniqNum[num] = 1;
} else {
uniqNum[num] ++;
}
};
arr.forEach(numCounter);
return Object.keys(uniqNum)
.sort((a,b) => uniqNum[b] - uniqNum[a]) // sort by frequency
.filter((val,ind,array) => uniqNum[array[0]] == uniqNum[val]) // leave only most frequent
.map(val => Number(val)); // convert text to number
}
console.log( JSON.stringify(mode([3,3,2,4,4])) ) // [3,4]
console.log( JSON.stringify(mode([2,4,3,3])) ) // [3]
答案 2 :(得分:1)
我认为只有对forEach
循环进行一点修改并辅助其他辅助数据结构才能完成:
function mode(arr) {
var freq = [], uniqNum = {}, i;
arr.forEach(function (num) {
uniqNum[num] = i = (uniqNum[num] || 0) + 1;
freq[i] = (freq[i] || []).concat(num);
});
return freq[freq.length - 1];
}
console.log(mode([1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 6, 6, 7, 1, 6]));
只需对数组的所有元素进行一次迭代,我们就可以收集足够的信息来打印出结果:
uniqNum
是您创建的用于收集有关元素频率的信息的集合。freq
将是一个数组,其中最后一个元素将包含一个具有更高频率元素的数组。Fiddle。希望它有所帮助。
答案 3 :(得分:0)
我尝试过使用原生js函数来解决这个问题。
var arr = [1,2,10,5,1];
// groupBy number
var x = arr.reduce(
function(ac, cur){
ac[cur]?(ac[cur] = ac[cur] + 1):ac[cur] = 1;
return ac;
}, {}
);
// sort in order of frequencies
var res = Object.keys(x).sort(
function(a,b){ return x[a] < x[b]}
);
res[0] has the most frequent element