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

例如,如果初始数组是:

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

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

5, 2, 9, 4

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

3, 5, 1, 1

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

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

谢谢:)


当前回答

编辑2020年:这是一个相当老的答案(9年)。扩展本机原型总是会引起讨论。尽管我认为程序员可以自由选择自己的编程风格,这里有一个(更现代的)方法来解决这个问题,而不需要扩展Array.prototype:

{ // create array with some pseudo random values (1 - 5) const arr = Array.from({length: 100}) .map( () => Math.floor(1 + Math.random() * 5) ); // frequencies using a reducer const arrFrequencies = arr.reduce((acc, value) => ({ ...acc, [value]: acc[value] + 1 || 1}), {} ) console.log(arrFrequencies); console.log(`Value 4 occurs ${arrFrequencies[4]} times in arrFrequencies`); // bonus: restore Array from frequencies const arrRestored = Object.entries(arrFrequencies) .reduce( (acc, [key, value]) => acc.concat(Array(value).fill(+key)), [] ); console.log(arrRestored.join()); } .as-console-wrapper { top: 0; max-height: 100% !important; }

旧的(2011年)答案是:你可以扩展Array。原型,像这样:

{ Array.prototype.frequencies = function() { var l = this.length, result = { all: [] }; while (l--) { result[this[l]] = result[this[l]] ? ++result[this[l]] : 1; } // all pairs (label, frequencies) to an array of arrays(2) for (var l in result) { if (result.hasOwnProperty(l) && l !== 'all') { result.all.push([l, result[l]]); } } return result; }; var freqs = [5, 5, 5, 2, 2, 2, 2, 2, 9, 4].frequencies(); console.log(`freqs[2]: ${freqs[2]}`); //=> 5 // or var freqs = '1,1,2,one,one,2,2,22,three,four,five,three,three,five' .split(',') .frequencies(); console.log(`freqs.three: ${freqs.three}`); //=> 3 // Alternatively you can utilize Array.map: Array.prototype.frequencies = function() { var freqs = { sum: 0 }; this.map(function(a) { if (!(a in this)) { this[a] = 1; } else { this[a] += 1; } this.sum += 1; return a; }, freqs); return freqs; } } .as-console-wrapper { top: 0; max-height: 100% !important; }

其他回答

Const arr = [2,2,5,2,2,2,4,5,5,9]; 函数foo(数组){ Let a = [], B = [], Arr =…, //克隆数组,这样我们在使用.sort()时不会改变原始数组 prev; arr.sort (); For (let元素的arr) { If (element !== prev) { a.push(元素); b.push (1); } + + b (b。长度- 1]; Prev =元素; } 返回[a, b]; } Const result = foo(arr); console.log('(' +结果[0 ] + ']','[' + 结果[1]+ ')') console.log (arr)

一行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 ()))

不要使用两个数组的结果,使用一个对象:

a      = [5, 5, 5, 2, 2, 2, 2, 2, 9, 4];
result = { };
for(var i = 0; i < a.length; ++i) {
    if(!result[a[i]])
        result[a[i]] = 0;
    ++result[a[i]];
}

然后结果将看起来像:

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

这个问题已经有8年的历史了,很多很多的答案都没有考虑到ES6及其众多的优势。

也许更重要的是,当我们创建额外的数组,创建数组的两倍或三倍副本,甚至将数组转换为对象时,考虑我们的代码对垃圾收集/内存管理的后果。对于小型应用来说,这些都是微不足道的观察结果,但如果规模化是一个长期目标,那么就要彻底考虑这些问题。

如果您只是需要一个特定数据类型的“计数器”,并且起点是一个数组(我假设您因此想要一个有序列表,并利用数组提供的许多属性和方法),那么您只需简单地遍历array1,并用array1中找到的这些值的值和出现次数填充array2。

就这么简单。

面向对象编程和面向对象设计的简单类SimpleCounter (ES6)的示例

class SimpleCounter { 

    constructor(rawList){ // input array type
        this.rawList = rawList;
        this.finalList = [];
    }

    mapValues(){ // returns a new array

        this.rawList.forEach(value => {
            this.finalList[value] ? this.finalList[value]++ : this.finalList[value] = 1;
        });

        this.rawList = null; // remove array1 for garbage collection

        return this.finalList;

    }

}

module.exports = SimpleCounter;

我认为这是最简单的方法如何计数发生在数组中相同的值。

var a = [true, false, false, false];
a.filter(function(value){
    return value === false;
}).length