Underscore.js: найти наиболее часто встречающееся значение в массиве?

Рассмотрим следующий простой массив:

var foods = ['hotdog', 'hamburger', 'soup', 'sandwich', 'hotdog', 'watermelon', 'hotdog'];

С underscore существует ли функция или комбинация функций, которые я могу использовать для выбора наиболее часто встречающегося значения (в данном случае это hotdog)?

Ответы

Ответ 1

_.chain(foods).countBy().pairs().max(_.last).head().value()

countBy: Сортирует список в группы и возвращает количество для количества объектов в каждой группе.

pairs: Преобразуйте объект в список пар [key, value].

max: Возвращает максимальное значение в списке. Если предоставляется функция итератора, она будет использоваться для каждого значения для генерации критерия, по которому оценивается значение.

last: Возвращает последний элемент массива

head: Возвращает первый элемент массива

chain: Возвращает обернутый объект. Методы вызова для этого объекта будут продолжать возвращать завернутые объекты до тех пор, пока не будет использовано значение.

value: Извлекает значение обернутого объекта.

Ответ 2

Вы можете сделать это за один проход, используя _.reduce. Основная идея состоит в том, чтобы отслеживать частоты слов и наиболее распространенное слово одновременно:

var o = _(foods).reduce(function(o, s) {
    o.freq[s] = (o.freq[s] || 0) + 1;
    if(!o.freq[o.most] || o.freq[s] > o.freq[o.most])
        o.most = s;
    return o;
}, { freq: { }, most: '' });

Это оставляет 'hotdot' в o.most.

Демо: http://jsfiddle.net/ambiguous/G9W4m/

Вы также можете сделать это с помощью each (или даже простого цикла for), если вы не против предварительного кэширования кеша переменная:

var o = { freq: { }, most: '' };
_(foods).each(function(s) {
    o.freq[s] = (o.freq[s] || 0) + 1;
    if(!o.freq[o.most] || o.freq[s] > o.freq[o.most])
        o.most = s;
});

Демо: http://jsfiddle.net/ambiguous/WvXEV/

Вы также можете разбить o на две части и использовать слегка измененную версию выше, тогда вам не нужно было бы говорить o.most, чтобы получить 'hotdog'.