在Javascript中,我试图采取数字值的初始数组,并计算其中的元素。理想情况下,结果将是两个新数组,第一个数组指定每个唯一元素,第二个数组包含每个元素出现的次数。但是,我愿意听取关于输出格式的建议。

例如,如果初始数组是:

5, 5, 5, 2, 2, 2, 2, 2, 9, 4

然后将创建两个新数组。第一个将包含每个唯一元素的名称:

5, 2, 9, 4

第二个将包含该元素在初始数组中出现的次数:

3, 5, 1, 1

因为数字5在初始数组中出现了三次,数字2出现了五次,9和4都出现了一次。

我一直在寻找解决方案,但似乎没有一个可行,而且我自己尝试过的每件事最后都出奇地复杂。任何帮助都将不胜感激!

谢谢:)


当前回答

2021年的版本

更优雅的方法是使用逻辑空赋值(x ??= y)结合数组#reduce()与O(n)时间复杂度。

主要思想仍然是使用array# reduce()将输出作为对象进行聚合,以获得最高的性能(时间和空间复杂度),就像其他答案一样,搜索和构造中间数组。

Const arr = [2,2,2,2,2,2,4,5,5,5,9]; Const result = arr。Reduce ((acc, curr) => { acc(咕咕叫)? ?= {[curr]: 0}; acc[咕咕叫][咕咕叫]+ +; 返回acc; }, {}); console.log (Object.values(结果));

清理和重构代码

使用逗号操作符(,)语法。

逗号操作符(,)计算它的每个操作数(从左到右) 右)并返回最后一个操作数的值。

Const arr = [2,2,2,2,2,2,4,5,5,5,9]; Const result = arr。减少((acc,咕咕叫)= > (acc[咕咕叫]= (acc(咕咕叫)| | 0)+ 1,acc), {}); console.log(结果);

输出

{
  "2": 5,
  "4": 1,
  "5": 3,
  "9": 1
}

其他回答

所以这里是我如何做的一些最新的javascript功能:

首先,将数组缩减为一个计数的Map:

let countMap = array.reduce(
  (map, value) => {map.set(value, (map.get(value) || 0) + 1); return map}, 
  new Map()
)

通过使用Map,您的起始数组可以包含任何类型的对象,并且计数将是正确的。如果没有Map,某些类型的对象会给你奇怪的计数。 关于区别的更多信息,请参阅Map文档。

如果你所有的值都是符号、数字或字符串,这也可以用在对象上:

let countObject = array.reduce(
  (map, value) => { map[value] = (map[value] || 0) + 1; return map },
  {}
)

或者使用解构和对象扩展语法,以一种没有突变的函数式方式略显花哨:

let countObject = array.reduce(
  (value, {[value]: count = 0, ...rest}) => ({ [value]: count + 1, ...rest }),
  {}
)

此时,您可以使用Map或对象进行计数(与对象不同,Map是直接可迭代的),或者将其转换为两个数组。

有关地图:

countMap.forEach((count, value) => console.log(`value: ${value}, count: ${count}`)

let values = countMap.keys()
let counts = countMap.values()

或者对于对象:

Object
  .entries(countObject) // convert to array of [key, valueAtKey] pairs
  .forEach(([value, count]) => console.log(`value: ${value}, count: ${count}`)

let values = Object.keys(countObject)
let counts = Object.values(countObject)
var aa = [1,3,5,7,3,2,4,6,8,1,3,5,5,2,0,6,5,9,6,3,5,2,5,6,8];
var newArray = {};
for(var element of aa){
  if(typeof newArray[element] === 'undefined' || newArray[element] === null){
    newArray[element] = 1;
  }else{
    newArray[element] +=1;
  }
}

for ( var element in newArray){
  console.log( element +" -> "+ newArray[element]);
}

一行ES6解决方案。这么多的答案使用对象作为地图,但我看不到任何人使用实际的地图

const map = arr.reduce((acc, e) => acc.set(e, (acc.get(e) || 0) + 1), new Map());

使用map.keys()获取唯一元素

使用map.values()来获取事件

使用map.entries()获取对[元素,频率]

Var arr = [5,5,5,2,2,2,2,2,2,2,9,4] Const map = arr。Reduce ((acc, e) => acc。set(e, (acc.get(e) || 0) + 1), new Map()); console.info([…map.keys ())) console.info([…map.values ())) console.info([…]. entry ()))

ES6版本应该更简单(另一个一行解决方案)

let arr = [5, 5, 5, 2, 2, 2, 2, 2, 9, 4];
let acc = arr.reduce((acc, val) => acc.set(val, 1 + (acc.get(val) || 0)), new Map());

console.log(acc);
// output: Map { 5 => 3, 2 => 5, 9 => 1, 4 => 1 }

Map代替普通对象帮助我们区分不同类型的元素,否则所有计数都是基于字符串

我对拉姆达的解决方案:

const testArray = [5, 5, 5, 2, 2, 2, 2, 2, 9, 4]

const counfFrequency = R.compose(
  R.map(R.length),
  R.groupBy(R.identity),
)

counfFrequency(testArray)

链接到REPL。