我正在尝试遍历一个数组,以便对总计进行分组和计算。
例如:
var farm = [['Cats', 3], ['Cats', 4], ['Mice', 2], ['Dogs', 5]];
我想通过并首先看到'猫',然后添加所有猫值,然后重复其他独特类别的过程。
最终输出将是:
Cats (7)
Mice (2)
Dogs (5)
目前,我正试图以这种方式完成它,但我显然在某个地方犯了一个菜鸟错误。
var farm = [];
farm.push(['Cats', 3], ['Cats', 4], ['Mice', 2], ['Dogs', 5]);
var animalCounter = function(array){
var list = '';
for(var i = 0; i<array.length; i++){
var animalID = array[i][0];
var animalCount = 0;
for (var x; x<array.length; x++){
if(animalID == array[x][0]){
animalCount += array[x][0] - 1;
}
list += animalID + " (" + animalCount + ")\n";
}
}
alert(list);
}
animalCounter(farm);
答案 0 :(得分:5)
使用一个物体将类似的动物加在一起
var farm = [];
farm.push(['Cats', 3], ['Cats', 4], ['Mice', 2], ['Dogs', 5]);
var o = {};
for (var i=farm.length; i--;) {
var key = farm[i][0],
val = farm[i][1];
o[key] = key in o ? o[key] + val : val;
}
然后很容易创建列表
for (var key in o) {
list += key + " (" + o[key] + ")\n";
}
答案 1 :(得分:1)
你错过了一个外层括号:
var farm = [['Cats', 3], ['Cats', 4], ['Mice', 2], ['Dogs', 5]];
你所拥有的将最终与
相同var farm = ['Dogs', 5];
逗号运算符在var
语句中执行奇怪的操作,尤其是,因为,
也会分隔各个变量声明和初始化。
答案 2 :(得分:1)
只是为了测试... (不太实用)
var farm = [['Cats', 3], ['Cats', 4], ['Mice', 2], ['Dogs', 5]];
farm.reduce(function(a, b, i){
var r = (i==1 ? a.slice() : a),
j = r.indexOf(b[0]);
if(j >= 0){
r[j+1] += b[1];
return r;
} else return r.concat(b);
}).reduce(function(a, b, i){
return i%2 ? a+' ('+b+')' : a+'\n'+b;
});
粗略解释:
迭代farm
的每个元素,将 2D 数组缩减为平面数组,其中每个 奇数 索引都是“count”对应前一个元素 - 注意检查 甚至 索引中的“key”是否已经存在于数组中(在这种情况下分别更新它的计数)。 slice
调用只是为了确保原始数组保持不变。这导致数组看起来像:
["Cats", 7, "Mice", 2, "Dogs", 5]
这个新数组再次减少,这次将每个元素连接成一个字符串 - 格式取决于当前迭代是否具有奇数或偶数索引。
Array.reduce
是旧浏览器(如果这很重要)不支持的功能之一,但MDN网站上有polyfill。
答案 3 :(得分:0)
我可能会做的有点不同:
var farm = [];
farm.push(['Cats', 3], ['Cats', 4], ['Mice', 2], ['Dogs', 5]);
var animalCounter = function(array){
var animalObject = {};
for(var i = 0; i<array.length; i++){
var animalID = array[i][0];
var animalCount = array[i][1];
if(animalObject[animalID]) {
animalObject[animalID] += animalCount;
} else {
animalObject[animalID] = animalCount;
}
}
return animalObject;
}
第一个函数animalCounter
创建一个对象,将动物名称映射到数组中的数字。因此,对于您的示例,它将返回如下所示的对象:
{ 'Cats': 7, 'Mice': 2, 'Dogs': 5 }
从那里开始,一旦你拥有了这个对象,创建一个字符串就能以你喜欢的任何格式输出这些数据是微不足道的:
var counter = animalCounter(farm);
var list = '';
for(var key in counter) {
list += key + ': ' + counter[key] + ', ';
}
console.log(list); //=> Cats: 7, Mice: 2, Dogs: 5,
您的初始函数不起作用的原因是因为它没有考虑到您的数组中可能有多个相同动物的实例。如果您的原始数组是[['Cats', 7], ['Mice', 2], ['Dogs', 5]]
,那就没问题了,但由于您的Cats
条目已被分割为['Cats', 4], ['Cats', 3]
,因此您的原始代码将其视为两个不同的动物。请注意我的功能:
if(animalObject[animalID]) {
animalObject[animalID] += animalCount;
} else {
animalObject[animalID] = animalCount;
}
代码检查动物是否已经存储在新对象中,如果是,则递增计数,而不是从0创建新计数器。这样就可以处理任何重复项。
答案 4 :(得分:0)
我看到三个问题:
var animalCount
在循环内部,那么你实际上为数组的每个元素都有一个全新的变量相反,试试这个:
var farm = [];
farm.push(['Cats', 3], ['Cats', 4], ['Mice', 2], ['Dogs', 5]);
var animalCounter = function (array) {
var list = '',
catsCount = 0,
miceCount = 0,
dogsCount = 0;
for (var i = 0; i < array.length; i++) {
var animalID = array[i][0];
var animalCount = array[i][1];
if (animalID === 'Cats') {
catsCount += animalCount;
} else if (animalID === 'Mice') {
miceCount += animalCount;
} else if (animalID === 'Dogs') {
dogsCount += animalCount;
}
}
list = 'Cats(' + catsCount + ') Mice(' + miceCount + ') Dogs(' + dogsCount + ')';
alert(list);
}
animalCounter(farm);
每种动物都有单独的变量,数组中的值会添加到正确的计数器变量中。
或者,对于更有条理的解决方案:
var farm = []; farm.push(['Cats',3],['Cats',4],['Mice',2], ['狗',5]);
var animalCounter = function(array){ var list ='', animalCounters = {}; for(var i = 0; i&lt; array.length; i ++){ var animalID = array [i] [0]; var animalCount = array [i] [1]; animalCounters [animalID] =(animalCounters [animalID] || 0)+ animalCount; }
for (var id in animalCounters) {
list += id + " (" + animalCounters[id] + ")\n";
}
alert(list);
} animalCounter(farm);
在此代码中,animalCounters变量是一个对象。 JavaScript对象就像关联数组一样,它允许我们使用动物ID字符串作为动物总和的整数的“关键字”。每种类型的动物都是animalCounters对象的属性,其中动物的总和为其值。
我在这里使用了一些略显晦涩的符号,所以我会解释一下。
animalCounters[animalID]
这只是引用对象属性的另一种方法。在JavaScript中,animalCounters.Cats
和animalCounters["Cats"]
访问相同的内容。但是,如果你不确定动物的类型是猫,你需要“猫”(或任何其他种类的动物)变量。 animalCounters["Cats"]
表示法带有一个字符串,所以你可以说这个并且它会起作用:
var animalID = "Dogs";
alert(animalCounters[animalID);// returns animalCounters.Dogs
animalCounters[animalID] = (animalCounters[animalID] || 0) + animalCount;
此处,(animalCounters[animalID] || 0)
表示如果 animalCounters[animalID]
已有值,请将该值添加到animalCount
,否则将0
添加到animalCount
。这是必要的,因为如果您在将animalCounters[animalID]
设置为任何内容之前尝试将animalCount
添加到animalCounters[animalID]
,则添加将无效。
答案 5 :(得分:0)
当你获得某种动物的数量时,你犯了一个简单的错误:
animalCount += array[x][0] - 1;
farm[x][0]
将始终返回动物的名称,这是一个字符串,因此当尝试从中减去 1 时,它将导致NaN
(非数字)。
也是循环的第一个:for(var i; i<array.length; i++){ ...
循环遍历所有数组插槽,即使它们已被计数,因此猫将被计数两次,因此猫不计算为7,它们将达到14。
您需要创建一个数组副本并取消已计数的插槽。棘手的部分是按值复制数组,因此对Temp的任何更改都不会更改farm (请参阅Copying Arrays):
var farm = [];
farm.push(['Cats', 3], ['Cats', 4], ['Mice', 2], ['Dogs', 5]);
function countAnimals(array) {
var Temp = [];
var d = 0;
//This while loop copies the array
while (d < farm.length) {
var s = array[d].toString();
Temp.push(s.split(","));
d++;
}
var list = "";
var done = 0;
while (done < array.length) {
if(Temp[0][1] == "Done") {
Temp.shift();
} else {
var animalID = Temp[0][0];
var count = parseFloat(Temp[0][1]);
Temp.shift();
var i = 0;
while (i < Temp.length) {
if(Temp[i][0] == animalID) {
count = count + parseFloat(Temp[i][1]);
Temp[i][1] = "Done";
}
i++;
}
list = list + "\n" + animalID + "("+count+")";
}
done++;
}
alert(list);
}
countAnimals(farm);