JavaScript:使用一个对象在数组上迭代并跟踪项目频率
JavaScript: Using an object to iterate over array and keep track of item frequency
我需要一个函数mostFrequentWord
来返回数组words
中最常见的字符串。我想用一个物体来跟踪这些单词的频率。使用getter和setter方法似乎是最可行的选择。其中setter函数用于更改表示单词的每个键的值。然后,在我按频率值对对象进行排序后,我可以返回频率最高的单词。我是不是想多了这个问题?
以下是如何使用Array.prototype.reduce()
解决此问题
var words = ["one", "three", "three", "three", "two", "two"];
var frequencies = words.reduce(function(memo, word) {
//either start the count now, if this is the first encounter or increas it by 1
memo[word] = (memo[word] + 1) || 1;
return memo;
}, {}); // note the empty object being passed in here - that's the initial value for the variable "memo"
console.log(frequencies);
var mostFrequentWord = Object.keys(frequencies)
.reduce(function(highest, current) {
return frequencies[highest] > frequencies[current] ? highest : current;
}, "");
console.log("most frequent word: " + mostFrequentWord +
"'ncount: " + frequencies[mostFrequentWord])
要获得最高值,只需再次运行reduce
即可,只是这次使用Object.keys()
发表评论:
在第一个循环中使用.reduce((比使用.forEach((有什么好处吗?你只是每次都返回相同的对象,所以看起来.forEach((也同样有效,而且可能会更清晰一点
好吧,这在一定程度上取决于风格——这两个都可以实现相同的结果。不过,他们的方式不同,因此我认为reduce
至少有微小的优势。原因如下:
- CCD_ 7和CCD_。虽然它们都可以用来实现类似的结果,但它们操作方式的差异确实使它们对某些操作有点偏见
- 对于CCD_ 9;我想把这些东西收集起来,仔细看一遍,然后归还一件东西"。例如,它非常适合查找最小值、最大值或总和。因此,如果您在开始时有一个数组,并且希望以其他内容结束,则可以使用它(尽管有时,您也可以返回一个数组(
forEach
的意图略有不同;我想浏览一下这个收藏,并对每一件物品做点什么;。从本质上讲,当你想对每个对象执行相同的操作时,比如说,你可能正在console.log
对它们进行标记、验证或上传。通常,您将有一个some代码,它接受一个项并对其执行某些操作,您只需通过forEach
将其应用于所有项
reduce
是自包含的。它可能看起来不多,也可能不多,这取决于上下文,但您必须认识到整个功能都包含在reduce
中。这使得在更大的背景下更容易掌握,因为你在一个地方拥有你需要的一切。让我们用forEach
重写它,我会尝试显示差异
var words = ["one", "three", "three", "three", "two", "two"];
var frequencies = {}; //<- instantiation needs to be separate
words.forEach(function(word) { //<- population needs to be separate
frequencies[word] = (frequencies[word] + 1) || 1;
});
console.log(frequencies); //<- usage is separate
因此,由于变量的实例化,您使函数缩短了一行(没有返回(,但增加了一行。现在看起来完全可以了,因为它是孤立的,但在更大的代码库中,每个部分之间可能都有代码。这让你很难把所有的逻辑都记在脑子里——如果你只阅读forEach
循环,你就没有完整的上下文,因为当你滚动到它时,你需要知道frequencies
,你可能看不到forEach
。更重要的是,你甚至不知道frequencies
会处于什么状态,然后你得到forEach
——它会预先填充一些值吗?会设置为null
吗?它会是一个数组而不是一个对象吗?您不仅必须找到frequencies
的初始声明,而且还必须跟踪是否在调用函数之前的任何时候发生了更改。
现在,话虽如此,让我们重新审视reduce
的作用——关于它如何运作,你需要了解的一切都在一个地方。frequencies
的声明、所有更改和最终赋值总是发生在三行代码的范围内,因此无论您有多少代码,都不需要为上下文找到任何其他有意义的东西。是的,您可能需要知道words
包含什么,但forEach
也是如此。
关于这两点,我想说reduce
更容易理解。forEach
看起来更简单的解决方案的唯一原因是,如果您只使用常规for
循环进行操作,并且需要进行功能替换。然而,声明式方法与命令式方法有其区别——forEach
和for
是不同的。两者都不是天生的更好,但根据情况,它们确实有优势和劣势。在这种情况下,reduce
操作是更好的功能方法。
它是这样的:
function inArrayToIndex(value, array){
for(var i=0,l=array.length; i<l; i++){
if(array[i] === value){
return i;
}
}
return false;
}
function mostFrequentWord(wordsArray){
var h = [], w, a, c = [], m;
for(var i=0,l=wordsArray.length; i<l; i++){
w = wordsArray[i]; a = inArrayToIndex(w, h)
if(a !== false){
c[a]++;
}
else{
h.push(w); c.push(1);
}
}
return h[inArrayToIndex(Math.max.apply(null, c), c)];
}
var mostest = mostFrequentWord(yourWordsArray);
感谢所有的投入。以下是我解决问题的方法。
首先,我从一个助手功能开始:
function getTokens(rawString) {
// returns an alphabetically sorted list of words, removing punctuation
// characters
return rawString.toLowerCase().split(/[ ,!.";:-]+/).filter(Boolean).sort();
}
然后我的主要功能如下:
function mostFrequentWord(words) {
var wordsArray = getTokens(words); // setup array for strings to live
var wordsObject = {}; // Setup object literal for words + count
for (var i=0; i<wordsArray.length; i++) {
var wordToCheck = wordsArray[i];
if (wordsObject[wordToCheck] == undefined) {
// word doesn't exist, let's add it as a key and set value pair to 1
console.log(wordToCheck + " not found. Adding to object.");
wordsObject[wordToCheck] = 1;
} else {
// word does exist, let's increment the value pair by 1
console.log(wordToCheck + " has been found. Incrementing.");
wordsObject[wordToCheck] += 1;
}
}
console.log(wordsObject);
var mostFrequent;
for (var key in wordsObject) {
if (mostFrequent == undefined) {
mostFrequent = key;
} else if (wordsObject[key] > wordsObject[mostFrequent]) {
mostFrequent = key;
}
}
console.log("Most frequent word is: " + mostFrequent);
return mostFrequent;
}
这里有另一个解决方案,它使用lodash
var words = ["bob", "bill", "jimmy", "jack", "bob", "bob", "jimmy"];
freq = {};
_.forEach(words, function (word) {
freq[word] = freq[word]++ || 1;
});
var max = 0,
mostFreq = undefined;
_.forEach(freq, function (count, word) {
if (count > max) {
max = count;
mostFreq = word;
}
});
console.log(mostFreq);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.15.0/lodash.min.js"></script>
for each函数是javascript中的原生函数,但仅适用于数组。使用lodash,您可以迭代数组的每个元素,或对象的每个键值对。对对象使用_.forEach时,传入回调的第一个参数是值,第二个参数是对象中每对的键。您应该查看lodash文档。它们提供了一些非常有用的工具。
您可以使用对象来保持单词索引计数,然后迭代计数以获得最高计数。下面是一个工作片段,说明:
function findMostFrequent(array) {
var map = {};
array.forEach(function(item) {
map[item] = (map[item] || 0) + 1;
});
// find highest word count
var highWord = Object.keys(map).reduce(function(highestWord, currentWord) {
return map[currentWord] > map[highestWord] ? currentWord : highestWord;
});
return {word: highWord, count: map[highWord]};
}
var words = ["hello", "goodbye", "hello", "hello", "whatever", "something", "goodbye"];
var result = findMostFrequent(words);
console.log("highest count word is " + result.word + ", count = " + result.count);
在ES6中,您可以使用Map
对象来保持计数,而不是使用普通的JS对象,尽管这两种方法在实现上几乎没有什么不同。
- 如何在javascript中迭代数字列表
- JS:检查URL中的参数,然后迭代一个参数为var的函数
- 如何迭代Array.prototype函数
- 如何使用jquery迭代具有相同属性的html元素并查找onclick事件
- 在ejs-partial中对JSON对象进行迭代
- 如何在DataTables 2.1中迭代对象数组
- 使用递归属性迭代保留属性结构
- 正在停止.在jquery中的特定时间间隔内,每次迭代的每次执行
- 如果30秒未单击,请应用CSS一次,将其删除,然后重新迭代
- 主干-从模板中迭代的集合中获取特定的模型
- 创建一个方法,通过一个窗口进行迭代并获取Titanium中的所有控件
- 什么's是在javascript中迭代项的最佳方式
- 为什么这只是迭代 HTMLCollection 的奇怪元素
- 是否“;对于的“;循环迭代遵循JavaScript中的数组顺序
- Babel编译错误:找不到模块核心js/library/fn/get迭代器
- 在es6中,将带有回调的事件侦听器设置为可迭代的
- jQuery-迭代不正确?(太长,无法执行)
- 为什么我达到了 $digest () 迭代?如何跟踪递归脚本的活动
- JavaScript:使用一个对象在数组上迭代并跟踪项目频率
- 在Javascript循环中运行PHP,以任何方式跟踪迭代