查找数组中出现频率最高的元素(不仅限于字符串)

5

有人能带我做一下这个练习吗? 编写一个JavaScript程序,查找数组中出现最频繁的项。

var arr1 = [3, 'a', 'a', 'a', 2, 3, 'a', 3, 'a', 2, 4, 9, 3];
var mf = 1;
var m = 0;
var item;

for (var i = 0; i < arr1.length; i++) {
  for (var j = i; j < arr1.length; j++) {
    if (arr1[i] == arr1[j]) m++;
    if (mf < m) {
      mf = m;
      item = arr1[i];
    }
  }

  m = 0;
}

alert(item + " ( " + mf + " times ) ");

我一直在Stack Overflow上查看一些类似的问题,但是找不到我想要的答案。

我的问题是:

  1. 我不明白为什么需要有两个for循环。

  2. 为什么需要 mfm。这似乎有点令人困惑。

  3. 是否有其他解决方案?


1
可能是重复的问题:在数组中获取出现次数最高的元素 - Tushar
1
你应该在问题中包含相关的代码 - 这是 StackOverflow 的政策,因为外部链接往往会消失或随时间改变,导致一些问题在未来变得无用,因为已经无法获取完整的上下文信息。 - jfriend00
这不是关于JavaScript的问题,而是算法理论的问题。如果你想更深入地了解,可以寻找在线算法理论课程(Coursera?)或讲座(Stanford?)。 - stdob--
如果你还在寻找答案!http://stackoverflow.com/questions/40410470/highest-occurrence-in-an-array-or-first-selected/40410898#40410898 - daanvanham
8个回答

4

我认为这个解决方案中没有必要使用两个循环。你可以看一下这个原型代码,它使用了一个简单的数据结构叫做map:

var arr=[3, 'a', 'a', 'a', 2, 3, 'a', 3, 'a', 2, 4, 9, 3];
var map = {};
var mostFrequentElement = arr[0];
function findMostFrequent(){
    for(var i = 0; i<arr.length; i++){
        if(!map[arr[i]]){
            map[arr[i]]=1;
        }else{
            ++map[arr[i]];
            if(map[arr[i]]>map[mostFrequentElement]){
                mostFrequentElement = arr[i];
            }
        }
    }
    alert(mostFrequentElement);
}

3

用户想要代码的解释:

在这里,他们选择数组的第一个元素并将其与后面的每个元素进行比较。

然后,每次相同的元素再次出现时,计数器m就会增加,即该元素的频率。

还保留了一个变量mf来跟踪最大频率。根据当前元素的频率将元素的频率与最大频率进行比较,并更新itemmf

var arr1=[3, 'a', 'a', 'a', 2, 3, 'a', 3, 'a', 2, 4, 9, 3]; //array
var mf = 1; //default maximum frequency
var m = 0;  //counter
var item;  //to store item with maximum frequency
for (var i=0; i<arr1.length; i++)    //select element (current element)
{
        for (var j=i; j<arr1.length; j++)   //loop through next elements in array to compare calculate frequency of current element
        {
                if (arr1[i] == arr1[j])    //see if element occurs again in the array
                 m++;   //increment counter if it does
                if (mf<m)   //compare current items frequency with maximum frequency
                {
                  mf=m;      //if m>mf store m in mf for upcoming elements
                  item = arr1[i];   // store the current element.
                }
        }
        m=0;   // make counter 0 for next element.
}

2

我不明白为什么需要两个for循环。

除了作者的选择外,没有必要使用两个循环。

为什么需要使用 mfm。看起来有点混乱。

它们是作者所选择的解决方案所必需的。

m 是正在测试的当前值的计数。

mf 是当前最大频率,用于测试 m 是否比以前的最高频率更频繁,并做出决策。

还有其他的解决方法吗?

当然,有很多。这里是另一种更进一步的解决方案。

function getMostFrequentElement(inputArg) {
    var type = typeof inputArg,
        length,
        mostFrequent,
        counts,
        index,
        value;
    
    if (inputArg === null || type === 'undefined') {
        throw TypeError('inputArg was "null" or "undefined"');
    }

    mostFrequent = [];
    if (type === 'function' || !Object.prototype.hasOwnProperty.call(inputArg, 'length')) {
        mostFrequent[0] = inputArg;
        mostFrequent[1] = 1;
    } else {
        counts = {};
        length = inputArg.length;
        for (index = 0; index < length; index += 1) {
            value = inputArg[index];
            type = typeof value;
            counts[type] = counts[type] || {};
            counts[type][value] = (counts[type][value] || 0) + 1;
            if (!mostFrequent.length || counts[type][value] >= mostFrequent[1]) {
                mostFrequent[0] = value;
                mostFrequent[1] = counts[type][value];
            }
        }
    }

    return mostFrequent;
}

function logMostFrequentElement(inputArg) {
    var mostFrequentElement,
    element,
    text;

    try {
        mostFrequentElement = getMostFrequentElement(inputArg)
        if (mostFrequentElement.length) {
            element = mostFrequentElement[0];
            if (typeof element === 'string') {
                element = '"' + element + '"';
            }

            text = element + ' ( ' + mostFrequentElement[1] + ' times )';
        } else {
            text = 'No elements';
        }
    } catch (e) {
        text = e.message;
    }

    document.getElementById('out').appendChild(document.createTextNode(text + '\n'));
}

logMostFrequentElement();
logMostFrequentElement(1);
logMostFrequentElement(true);
logMostFrequentElement(function (x) { return x; });
logMostFrequentElement(/ab/g);
logMostFrequentElement([]);
logMostFrequentElement([1, 2]);
logMostFrequentElement([1, NaN, 2, NaN, 'NaN']);
logMostFrequentElement([1, Infinity, 2, Infinity, 'Infinity', -Infinity]);
logMostFrequentElement(['1', '2', 1, '2', 2]);
logMostFrequentElement([3, 'a', 'a', 'a', 2, 3, 'a', 3, 'a', 2, 4, 9, 3]);
logMostFrequentElement([34, 'ab', 'ab', 'ab', 21, 34, 'ab', 34, 'ab', 21, 45, 99, 34]);
logMostFrequentElement('Also works with strings.');
<pre id="out"></pre>


1
使用 Array.prototype.reduce() 和一个临时变量,你可以这样做(4行):

var arr2 = [3, 'a', 'a', 'a', 2, 3, 'a', 3, 'a', 2, 4, 9, 3];
var newArr = arr2.slice().sort(), most = [undefined, 0], counter = 0;

newArr.reduce(function(old, chr){
   old == chr ? ++counter > most[1] && (most = [chr, counter]) : (counter = 1)
   return chr
});

alert(most[0] + " ( "+most[1]+" times )");

说明 请原谅我的英语。

使用Array.prototype.reduce()可以简化你的工作。以下函数首先将字符排序为22333349aaaaa,然后按顺序计算字符数。我创建了一个临时变量most来存储最常重复的字符数据。

注意这仅适用于单个数字的项目。


1
这是使用下划线回答第(3)点的答案:
function length(a) { return a.length; }

_.max(_.groupBy(arr1), length)[0]

这是如何工作的:

> arr1 = [3, 'a', 'a', 'a', 2, 3, 'a', 3, 'a', 2, 4, 9, 3];

> groups = _.groupBy(arr1)
< { 2: [2,2], 3: [3,3,3,3], 4: [4], 9: [9], a: ['a', 'a', ...] }

> max_group = _.max(groups, length)
< ['a', 'a', ...]

> max_group [0]
< 'a'

0
var nums = [3, 'a', 'a', 'a', 2, 3, 'a', 3, 'a', 2, 4, 9, 3]; //array
var freqs = {};
var max_index;
var max_value = -1/0; // Negative infinity.

$.each(nums, function(i, v) {
  if (freqs[v] != undefined) {
  freqs[v]++;
} else {
    freqs[v] = 1;
}
});


$.each(freqs, function(num, freq) {
  if (freq > max_value) {
      max_value = freq;
      max_index = num;
    }
});

if(max_index != undefined) {
    alert("Most common element is " + max_index + " with " + max_value + "  repetition(s).");
}

1
$ .each? 或许您想使用 Array.prototype.forEach。原帖提出了3个问题,但这并没有回答其中任何一个。 - RobG

0
请尝试这个。
var mostFrequnet = null,mostFrequnetItem ;
var arr1 = [3, 'a', 'a', 'a', 2, 3, 'a', 3, 'a', 2, 4, 9, 3];
arr1.sort();


for (var i=0;i<arr1.length;i++){ 

     var single = arr1[i]; 
     var total = (arr1.lastIndexOf(single)-arr1.indexOf(single))+1; 

     if(total > mostFrequnet) {

         mostFrequnetItem = arr1[i];
         mostFrequnet = total;
         i= arr1.lastIndexOf(single)+1;

    }
}

console.log(mostFrequnet);

console.log(mostFrequnetItem);

-1

mf是具有最高频率的数字的全局计数,而m是循环内部的本地计数


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