Answers:
很简单:
var count = 0;
for(var i = 0; i < array.length; ++i){
if(array[i] == 2)
count++;
}
const count = countItems(array, 2);
实现细节可以在内部争论。
[ 这个答案有点过时:请阅读编辑内容 ]
问好你的朋友:map
和filter
和reduce
和forEach
和every
等。
(由于块级作用域的缺失,我只是偶尔用JavaScript编写for循环,因此,如果您需要捕获或克隆迭代索引或值,则无论如何都必须使用函数作为循环的主体。For-loops通常效率更高,但有时您需要关闭。)
最易读的方式:
[....].filter(x => x==2).length
(我们本来可以写的.filter(function(x){return x==2}).length
)
以下内容更节省空间(O(1)而不是O(N)),但我不确定您会在时间方面付出多少好处/惩罚(自您访问以来,不多于常数)每个元素仅一次):
[....].reduce((total,x) => (x==2 ? total+1 : total), 0)
(如果需要优化这段代码,在某些浏览器中,for循环可能会更快一些……您可以在jsperf.com上进行测试。)
然后,您可以变得优雅,并将其转换为原型函数:
[1, 2, 3, 5, 2, 8, 9, 2].count(2)
像这样:
Object.defineProperties(Array.prototype, {
count: {
value: function(value) {
return this.filter(x => x==value).length;
}
}
});
您也可以将常规的旧的for循环技术(请参阅其他答案)保留在上述属性定义中(同样,这可能会更快)。
2017编辑:
糟糕,这个答案比正确答案更受欢迎。实际上,只需使用接受的答案即可。虽然这个答案可能很可爱,但是js编译器可能不会(或由于规范而无法)优化这种情况。因此,您应该真正编写一个简单的for循环:
Object.defineProperties(Array.prototype, {
count: {
value: function(query) {
/*
Counts number of occurrences of query in array, an integer >= 0
Uses the javascript == notion of equality.
*/
var count = 0;
for(let i=0; i<this.length; i++)
if (this[i]==query)
count++;
return count;
}
}
});
您可以定义.countStrictEq(...)
使用===
平等概念的版本。平等的概念可能对您所做的事情很重要!(例如[1,10,3,'10'].count(10)==2
,因为javascript中的数字如'4'== 4,因此调用它.countEq
或.countNonstrict
强调它使用==
运算符。)
还可以考虑使用自己的多集数据结构(例如python的“ collections.Counter
”),以避免不必首先进行计数。
class Multiset extends Map {
constructor(...args) {
super(...args);
}
add(elem) {
if (!this.has(elem))
this.set(elem, 1);
else
this.set(elem, this.get(elem)+1);
}
remove(elem) {
var count = this.has(elem) ? this.get(elem) : 0;
if (count>1) {
this.set(elem, count-1);
} else if (count==1) {
this.delete(elem);
} else if (count==0)
throw `tried to remove element ${elem} of type ${typeof elem} from Multiset, but does not exist in Multiset (count is 0 and cannot go negative)`;
// alternatively do nothing {}
}
}
演示:
> counts = new Multiset([['a',1],['b',3]])
Map(2) {"a" => 1, "b" => 3}
> counts.add('c')
> counts
Map(3) {"a" => 1, "b" => 3, "c" => 1}
> counts.remove('a')
> counts
Map(2) {"b" => 3, "c" => 1}
> counts.remove('a')
Uncaught tried to remove element a of type string from Multiset, but does not exist in Multiset (count is 0 and cannot go negative)
旁注:但是,如果您仍然希望使用函数式编程的方式(或者在不重写Array.prototype的情况下使用一次性的方法),那么现在可以将其编写得更加简洁[...].filter(x => x==2).length
。如果您关心性能,请注意,尽管这与for循环(O(N)时间)渐近相同,但它可能需要O(N)额外的内存(而不是O(1)内存),因为它将几乎当然会生成一个中间数组,然后计算该中间数组的元素。
array.reduce(function(total,x){return x==value? : total+1 : total}, 0)
[...].reduce(function(total,x){return x==2 ? total+1 : total}, 0)
const count = (list) => list.filter((x) => x == 2).length
。然后通过调用count(list)
list是数字数组来使用它。您还可以const count = (list) => list.filter((x) => x.someProp === 'crazyValue').length
对对象数组中的crazyValue实例进行计数。请注意,它与属性完全匹配。
ES6更新到JS:
请注意,您应始终使用三等号:===
以获得正确的比较:
// Let has local scope
let array = [1, 2, 3, 5, 2, 8, 9, 2]
// Functional filter with an Arrow function
array.filter(x => x === 2).length // -> 3
JS中的以下一致的Arrow函数(lambda函数):
(x) => {
const k = 2
return k * x
}
对于单个输入,可以简化为以下简洁形式:
x => 2 * x
其中return
的暗示。
不使用循环通常意味着将流程移交给某些确实使用循环的方法。
这是我们的循环讨厌编码器可以满足他的厌恶要求的一种方式:
var a=[1, 2, 3, 5, 2, 8, 9, 2];
alert(String(a).replace(/[^2]+/g,'').length);
/* returned value: (Number)
3
*/
您也可以重复调用indexOf(如果它可用作数组方法),并每次移动搜索指针。
这不会创建新的数组,并且循环比forEach或filter更快。
如果您有100万会员,这可能会有所作为。
function countItems(arr, what){
var count= 0, i;
while((i= arr.indexOf(what, i))!= -1){
++count;
++i;
}
return count
}
countItems(a,2)
/* returned value: (Number)
3
*/
String(a).match(/2/g).length + 1
-尽管请注意,否则您的实现对两位数不利。
大多数发布的使用数组函数(例如filter)的解决方案都不完整,因为它们没有参数化。
这里有一个解决方案,可以在运行时设置要计数的元素。
function elementsCount(elementToFind, total, number){
return total += number==elementToFind;
}
var ar = [1, 2, 3, 5, 2, 8, 9, 2];
var elementToFind=2;
var result = ar.reduce(elementsCount.bind(this, elementToFind), 0);
这种方法的优点是可以轻松更改函数以对例如大于X的元素数进行计数。
您也可以内联声明reduce函数
var ar = [1, 2, 3, 5, 2, 8, 9, 2];
var elementToFind=2;
var result = ar.reduce(function (elementToFind, total, number){
return total += number==elementToFind;
}.bind(this, elementToFind), 0);
var elementToFind=2; ... function (elementToFind, total, number){ return total += number==elementToFind; }.bind(this, elementToFind) ...
很难阅读,比正义没有优势... (acc, x) => acc += number == 2...
。我喜欢您使用,+=
而不是acc + (number == 2)
。虽然感觉像是不必要的语法HACK。
真的,您为什么需要map
或filter
为此?
reduce
这类操作是“天生的”:
[1, 2, 3, 5, 2, 8, 9, 2].reduce( (count,2)=>count+(item==val), 0);
而已!(如果item==val
在每次迭代中,然后1将被添加到累加器count
,如true
将解析到1
)。
作为功能:
function countInArray(arr, val) {
return arr.reduce((count,item)=>count+(item==val),0)
}
或者,继续扩展数组:
Array.prototype.count = function(val) {
return this.reduce((count,item)=>count+(item==val),0)
}
最好将其包装为函数:
let countNumber = (array,specificNumber) => {
return array.filter(n => n == specificNumber).length
}
countNumber([1,2,3,4,5],3) // returns 1
这是一种ES2017 +方法,用于获取O(N)中所有数组项的计数:
const arr = [1, 2, 3, 5, 2, 8, 9, 2];
const counts = {};
arr.forEach((el) => {
counts[el] = counts[el] ? (counts[el] += 1) : 1;
});
您还可以选择对输出进行排序:
const countsSorted = Object.entries(counts).sort(([_, a], [__, b]) => a - b);
您的示例数组的console.log(countsSorted):
[
[ '2', 3 ],
[ '1', 1 ],
[ '3', 1 ],
[ '5', 1 ],
[ '8', 1 ],
[ '9', 1 ]
]
我相信您正在寻找的是功能性方法
const arr = ['a', 'a', 'b', 'g', 'a', 'e'];
const count = arr.filter(elem => elem === 'a').length;
console.log(count); // Prints 3
elem ==='a'是条件,用您自己的条件替换。
count = arr.filter(elem => elem === 'a').length
还是count = arr.filter(elem => {return elem === 'a'}).length
我是js数组的reduce函数的初学者。
const myArray =[1, 2, 3, 5, 2, 8, 9, 2];
const count = myArray.reduce((count, num) => num === 2 ? count + 1 : count, 0)
实际上,如果您真的想花哨的话,可以在Array原型上创建一个count函数。然后,您可以重用它。
Array.prototype.count = function(filterMethod) {
return this.reduce((count, item) => filterMethod(item)? count + 1 : count, 0);
}
然后做
const myArray =[1, 2, 3, 5, 2, 8, 9, 2]
const count = myArray.count(x => x==2)
递归求解
function count(arr, value) {
if (arr.length === 1) {
return arr[0] === value ? 1 : 0;
} else {
return (arr.shift() === value ? 1 : 0) + count(arr, value);
}
}
count([1,2,2,3,4,5,2], 2); // 3
filter
,reduce
或简单forLoop
,而且在性能看时更昂贵,但仍与递归做的好方法。我唯一的变化是:我只是认为最好创建一个函数并在其中添加一个过滤器以复制数组,并避免原始数组的突变,然后将递归用作内部函数会更好。
var arrayCount = [1,2,3,2,5,6,2,8];
var co = 0;
function findElement(){
arrayCount.find(function(value, index) {
if(value == 2)
co++;
});
console.log( 'found' + ' ' + co + ' element with value 2');
}
我会做这样的事情:
var arrayCount = [1,2,3,4,5,6,7,8];
function countarr(){
var dd = 0;
arrayCount.forEach( function(s){
dd++;
});
console.log(dd);
}
在核心级文件中为Array类创建一个新方法,并在整个项目中使用它。
// say in app.js
Array.prototype.occurrence = function(val) {
return this.filter(e => e === val).length;
}
在您的项目中的任何地方使用它-
[1, 2, 4, 5, 2, 7, 2, 9].occurrence(2);
// above line returns 3
根据您要如何运行它:
const reduced = (array, val) => { // self explanatory
return array.filter((element) => element === val).length;
}
console.log(reduced([1, 2, 3, 5, 2, 8, 9, 2], 2));
// 3
const reducer = (array) => { // array to set > set.forEach > map.set
const count = new Map();
const values = new Set(array);
values.forEach((element)=> {
count.set(element, array.filter((arrayElement) => arrayElement === element).length);
});
return count;
}
console.log(reducer([1, 2, 3, 5, 2, 8, 9, 2]));
// Map(6) {1 => 1, 2 => 3, 3 => 1, 5 => 1, 8 => 1, …}
您可以在JavaScript数组中使用length属性:
var myarray = [];
var count = myarray.length;//return 0
myarray = [1,2];
count = myarray.length;//return 2