Underscore.js:如何在数组中找到出现最频繁的值?

17
请问需要翻译成中文吗?如果是的话,翻译如下:

考虑以下简单的数组:

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

使用 underscore,是否有函数或函数组合可用于选择最常出现的值(在本例中为 hotdog)?

3个回答

45

var foods = ['hotdog', 'hamburger', 'soup', 'sandwich', 'hotdog', 'watermelon', 'hotdog'];
var result = _.chain(foods).countBy().pairs().max(_.last).head().value();
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore.js"></script>

countBy: 将列表按组进行排序,并返回每个组中对象的数量计数。

pairs: 将对象转换为[key,value]对列表。

max: 返回列表中的最大值。如果提供了迭代器函数,则会在每个值上使用它来生成排名该值的标准。

last: 返回数组的最后一个元素

head: 返回数组的第一个元素

chain: 返回一个包装对象。在此对象上调用方法将继续返回包装对象,直到使用value。

value: 提取包装对象的值。


3
这非常聪明 :-D - gen_Eric
也许可以省略 .head,这样就可以得到计数:["hotdog", 3] - Bergi
5
建议使用max(_.last)代替lambda表达式。 - georg
5
如果您正在使用lodash,请将.pairs()替换为.toPairs(),将.max替换为.maxBy。 - Alex0007
如果我尝试对事物进行排序,有没有比这更优雅的方法呢? _(_.chain(foods).countBy().pairs().value()).sortBy(1).reverse() - Toucouleur
非常棒的答案,天才啊。这展示了函数式编程的强大之处。希望有一天我也能写出这样的代码。 :-) - hhsadiq

4
你可以使用_.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'了。


0

根据之前的答案,这是我用于计算字符串或数字数组的众数(当值具有相等频率时考虑平局),并返回频率的版本。然后您可以选择要对它们进行什么处理。

包括Underscore和Lodash。

// returns
// [['item', frequency]] where item is a string and frequency is an interger
// [['item', frequency], ['item', frequency], ['item', frequency] ... ] for draws

// examples:
// unique mode: creed appears the most times in array
// returns: [['creed', 4]]

// draw mode: 'jim' and 'creed' both occur 4 times in array
// returns: [['jim', 4], ['creed', 4]]

// underscore:
const usMode = arr => _.chain(arr).countBy().pairs().value().sort((a, b) => b[1] - a[1]).filter((e,i,a) => e[1] === a[0][1])

// lodash
const ldMode = arr => _.chain(arr).countBy().toPairs().value().sort((a, b) => b[1] - a[1]).filter((e,i,a) => e[1] === a[0][1])

// usage
usMode([1,2,3,3,3,4,5,6,7])
// [['3', 3]]

使用下划线:

// underscore

const strsUniqueArr = ['jim','pam','creed','pam','jim','creed','creed','creed']
const strsDrawArr = ['pam','jim','creed','jim','jim','creed','creed','creed', 'pam', 'jim']
const numsUniqueArr = [1, 2, 2, 2, 2, 3 ,4, 5]
const numsDrawArr = [1, 1, 1, 1, 2, 2, 2, 2, 3 ,4, 5]

const usMode = arr =>  _.chain(arr).countBy().pairs().value().sort((a, b) => b[1] - a[1]).filter((e,i,a) => e[1] === a[0][1])

console.log('empty', usMode([]))
console.log('unique strs', usMode(strsUniqueArr))
console.log('draw sts', usMode(strsDrawArr))
console.log('unique nums', usMode(numsUniqueArr))
console.log('draw nums', usMode(numsDrawArr))
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.9.1/underscore-min.js"></script>

使用lodash:

// lodash

const strsUniqueArr = ['jim','pam','creed','pam','jim','creed','creed','creed']
const strsDrawArr = ['pam','jim','creed','jim','jim','creed','creed','creed', 'pam', 'jim']
const numsUniqueArr = [1, 2, 2, 2, 2, 3 ,4, 5]
const numsDrawArr = [1, 1, 1, 1, 2, 2, 2, 2, 3 ,4, 5]

const ldMode = arr =>  _.chain(arr).countBy().toPairs().value().sort((a, b) => b[1] - a[1]).filter((e,i,a) => e[1] === a[0][1])

console.log('empty', ldMode([]))
console.log('unique strs', ldMode(strsUniqueArr))
console.log('draw sts', ldMode(strsDrawArr))
console.log('unique nums', ldMode(numsUniqueArr))
console.log('draw nums', ldMode(numsDrawArr))
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.min.js"></script>


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