计算数组元素的出现次数/频率

2020/10/13 12:21 · javascript ·  · 0评论

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

例如,如果初始数组为:

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

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

5, 2, 9, 4

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

3, 5, 1, 1

因为数字5在初始数组中出现3次,所以数字2出现5次,而9和4都出现一次。

我已经寻找了很多解决方案,但是似乎没有任何效果,而且我尝试过的一切都变得异常复杂。任何帮助,将不胜感激!

谢谢 :)

干得好:

现场演示: http : //jsfiddle.net/simevidas/bnACW/

注意

这将使用以下命令更改原始输入数组的顺序 Array.sort

var arr = [2, 2, 2, 2, 2, 4, 5, 5, 5, 9];

function foo(arr) {
  var a = [],
    b = [],
    prev;

  arr.sort();
  for (var i = 0; i < arr.length; i++) {
    if (arr[i] !== prev) {
      a.push(arr[i]);
      b.push(1);
    } else {
      b[b.length - 1]++;
    }
    prev = arr[i];
  }

  return [a, b];
}

var result = foo(arr);
console.log('[' + result[0] + ']','[' + result[1] + ']')

您可以使用一个对象保存结果:

var arr = [5, 5, 5, 2, 2, 2, 2, 2, 9, 4];
var counts = {};

for (var i = 0; i < arr.length; i++) {
  var num = arr[i];
  counts[num] = counts[num] ? counts[num] + 1 : 1;
}

console.log(counts[5], counts[2], counts[9], counts[4]);

因此,现在您的计数对象可以告诉您特定数字的计数:

console.log(counts[5]); // logs '3'

如果要获取成员数组,请使用keys()函数

keys(counts); // returns ["5", "2", "9", "4"]
var a = [5, 5, 5, 2, 2, 2, 2, 2, 9, 4].reduce(function (acc, curr) {
  if (typeof acc[curr] == 'undefined') {
    acc[curr] = 1;
  } else {
    acc[curr] += 1;
  }

  return acc;
}, {});

// a == {2: 5, 4: 1, 5: 3, 9: 1}

如果使用下划线或破折号,这是最简单的操作:

_.countBy(array);

这样:

_.countBy([5, 5, 5, 2, 2, 2, 2, 2, 9, 4])
=> Object {2: 5, 4: 1, 5: 3, 9: 1}

正如其他人所指出的,然后可以对结果执行_.keys()_.values()函数,以分别获取唯一的数字及其出现的位置。但是以我的经验,原始对象要容易得多。

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

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]];
}

然后result看起来像:

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

ECMAScript2015选项如何。

const a = [5, 5, 5, 2, 2, 2, 2, 2, 9, 4];

const aCount = new Map([...new Set(a)].map(
    x => [x, a.filter(y => y === x).length]
));
aCount.get(5)  // 3
aCount.get(2)  // 5
aCount.get(9)  // 1
aCount.get(4)  // 1

本示例将输入数组传递给Set构造函数,以创建唯一的集合然后,spread语法会将这些值扩展到一个新的数组中,以便我们可以调用map并将其转换为[value, count]成对的二维数组-即以下结构:

Array [
   [5, 3],
   [2, 5],
   [9, 1],
   [4, 1]
]

然后将新数组传递给Map构造函数,从而生成一个可迭代的对象:

Map {
    5 => 3,
    2 => 5,
    9 => 1,
    4 => 1
}

关于Map对象的妙处在于它保留了数据类型-也就是说aCount.get(5)将返回3aCount.get("5")将返回undefined它还允许将任何值/类型用作键,这意味着此解决方案也可以与对象数组一起使用。

我认为这是最简单的方法来计算数组中具有相同值的出现次数。

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

一线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, 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([...map.entries()])
const data = [5, 5, 5, 2, 2, 2, 2, 2, 9, 4]

function count(arr) {
  return arr.reduce((prev, curr) => (prev[curr] = ++prev[curr] || 1, prev), {})
}

console.log(count(data))

如果您偏爱单一衬板。

arr.reduce(function(countMap, word) {countMap[word] = ++countMap[word] || 1;return countMap}, {});

编辑(6/12/2015):由内而外的解释。countMap是一个映射图,它用单词的频率映射单词,我们可以看到匿名函数。reduce所做的是将带有参数的函数应用于所有数组元素,并将countMap作为最后一个函数调用的返回值传递。最后一个参数({})是第一个函数调用的countMap的默认值。

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而不是Plain Object可以帮助我们区分不同类型的元素,否则所有计数都基于字符串

基于答案@adamse@pmandell(我给予好评),在ES6你能做到这一点的一条线

  • 2017 edit:我||用来减少代码大小并使它更具可读性。
var a=[7,1,7,2,2,7,3,3,3,7,,7,7,7];
alert(JSON.stringify(

a.reduce((r,k)=>{r[k]=1+r[k]||1;return r},{})

));

它可以用来计算字符

var s="ABRACADABRA";
alert(JSON.stringify(

s.split('').reduce((a, c)=>{a[c]++?0:a[c]=1;return a},{})

));

如果您使用下划线,则可以使用功能路线

a = ['foo', 'foo', 'bar'];

var results = _.reduce(a,function(counts,key){ counts[key]++; return counts },
                  _.object( _.map( _.uniq(a), function(key) { return [key, 0] })))

所以你的第一个数组是

_.keys(results)

第二个数组是

_.values(results)

如果可用,其中大多数将默认为本地javascript函数

演示:http : //jsfiddle.net/dAaUU/

这只是轻松轻巧的东西...

function count(a,i){
 var result = 0;
 for(var o in a)
  if(a[o] == i)
   result++;
 return result;
}

编辑:既然你想要所有的事情...

function count(a){
 var result = {};
 for(var i in a){
  if(result[a[i]] == undefined) result[a[i]] = 0;
  result[a[i]]++;
 }
 return result;
}

具有reduce(固定)的ES6解决方案:

const arr = [2, 2, 2, 3, 2]

const count = arr.reduce((pre, cur) => (cur === 2) ? ++pre : pre, 0)
console.log(count) // 4

因此,这就是我将如何使用一些最新的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 }),
  {}
)

此时,您可以使用Mapor对象进行计数(与对象不同,地图可以直接迭代),也可以将其转换为两个数组。

对于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)

编辑2020年:这是一个相当老的答案(九年)。扩展本机prototype将始终引起讨论尽管我认为程序员可以自由选择自己的编程风格,但这是一种(更现代的)解决问题的方法,而无需扩展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(`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.prototype

var array = [5, 5, 5, 2, 2, 2, 2, 2, 9, 4];

function countDuplicates(obj, num){
  obj[num] = (++obj[num] || 1);
  return obj;
}

var answer = array.reduce(countDuplicates, {});
// answer => {2:5, 4:1, 5:3, 9:1};

如果仍然需要两个数组,则可以使用像这样的答案...

var uniqueNums = Object.keys(answer);
// uniqueNums => ["2", "4", "5", "9"];

var countOfNums = Object.keys(answer).map(key => answer[key]);
// countOfNums => [5, 1, 3, 1];

或者如果您希望uniqueNums为数字

var uniqueNums = Object.keys(answer).map(key => +key);
// uniqueNums => [2, 4, 5, 9];

使用O(n)时间复杂度的地图的解决方案

var arr = [2, 2, 2, 2, 2, 4, 5, 5, 5, 9];

const countOccurrences = (arr) => {
    const map = {};
    for ( var i = 0; i < arr.length; i++ ) {
        map[arr[i]] = ~~map[arr[i]] + 1;
    }
    return map;
}

演示:http//jsfiddle.net/simevidas/bnACW/

我的ramda解决方案:

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。

使用MAP,您可以在输出中包含2个数组:一个包含事件的数组,另一个包含事件的数量。

const dataset = [2,2,4,2,6,4,7,8,5,6,7,10,10,10,15];
let values = [];
let keys = [];

var mapWithOccurences = dataset.reduce((a,c) => {
  if(a.has(c)) a.set(c,a.get(c)+1);
  else a.set(c,1);
  return a;
}, new Map())
.forEach((value, key, map) => {
  keys.push(key);
  values.push(value);
});


console.log(keys)
console.log(values)

我们可以使用一种更好,更简单的方法来执行此操作ramda.js
这里的代码示例

const ary = [5, 5, 5, 2, 2, 2, 2, 2, 9, 4];
R.countBy(r=> r)(ary)

countBy文档在
文档中

使用Lodash

const values = [5, 5, 5, 2, 2, 2, 2, 2, 9, 4];
const frequency = _.map(_.groupBy(values), val => ({ value: val[0], frequency: val.length }));
console.log(frequency);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.min.js"></script>

我知道这个问题很旧,但是我意识到解决方案太少了,您只需很少的代码就可以得到count数组,所以这是我的问题

// The initial array we want to count occurences
var initial = [5, 5, 5, 2, 2, 2, 2, 2, 9, 4];  

// The count array asked for
var count = Array.from(new Set(initial)).map(val => initial.filter(v => v === val).length);  

// Outputs [ 3, 5, 1, 1 ]

另外,您可以从初始数组中获取集合

var set = Array.from(new Set(initial));  

//set = [5, 2, 9, 4]  

查看下面的代码。

<html>
<head>
<script>
// array with values
var ar = [5, 5, 5, 2, 2, 2, 2, 2, 9, 4];

var Unique = []; // we'll store a list of unique values in here
var Counts = []; // we'll store the number of occurances in here

for(var i in ar)
{
    var Index = ar[i];
    Unique[Index] = ar[i];
    if(typeof(Counts[Index])=='undefined')  
        Counts[Index]=1;
    else
        Counts[Index]++;
}

// remove empty items
Unique = Unique.filter(function(){ return true});
Counts = Counts.filter(function(){ return true});

alert(ar.join(','));
alert(Unique.join(','));
alert(Counts.join(','));

var a=[];

for(var i=0; i<Unique.length; i++)
{
    a.push(Unique[i] + ':' + Counts[i] + 'x');
}
alert(a.join(', '));

</script>
</head>
<body>

</body>
</html>

尝试这个:

Array.prototype.getItemCount = function(item) {
    var counts = {};
    for(var i = 0; i< this.length; i++) {
        var num = this[i];
        counts[num] = counts[num] ? counts[num]+1 : 1;
    }
    return counts[item] || 0;
}

我在代码战中解决了类似的问题,并设计了以下对我有用的解决方案。

这给出了数组中整数的最高计数,也给出了整数本身。我认为它也可以应用于字符串数组。

要正确排序字符串,请function(a, b){return a-b}sort()部分内部删除

function mostFrequentItemCount(collection) {
    collection.sort(function(a, b){return a-b});
    var i=0;
    var ans=[];
    var int_ans=[];
    while(i<collection.length)
    {
        if(collection[i]===collection[i+1])
        {
            int_ans.push(collection[i]);
        }
        else
        {
            int_ans.push(collection[i]);
            ans.push(int_ans);
            int_ans=[];
        }
        i++;
    }

    var high_count=0;
    var high_ans;

    i=0;
    while(i<ans.length)
    {
        if(ans[i].length>high_count)
        {
            high_count=ans[i].length;
            high_ans=ans[i][0];
        }
        i++;
    }
    return high_ans;
}

这是一种计算对象数组中出现次数的方法。它还会将第一个数组的内容放入新数组中以对值进行排序,以使原始数组中的顺序不会受到干扰。然后使用递归函数遍历每个元素并计算数组中每个对象的数量属性。

var big_array = [
  { name: "Pineapples", quantity: 3 },
  { name: "Pineapples", quantity: 1 },
  { name: "Bananas", quantity: 1 },
  { name: "Limes", quantity: 1 },
  { name: "Bananas", quantity: 1 },
  { name: "Pineapples", quantity: 2 },
  { name: "Pineapples", quantity: 1 },
  { name: "Bananas", quantity: 1 },
  { name: "Bananas", quantity: 1 },
  { name: "Bananas", quantity: 5 },
  { name: "Coconuts", quantity: 1 },
  { name: "Lemons", quantity: 2 },
  { name: "Oranges", quantity: 1 },
  { name: "Lemons", quantity: 1 },
  { name: "Limes", quantity: 1 },
  { name: "Grapefruit", quantity: 1 },
  { name: "Coconuts", quantity: 5 },
  { name: "Oranges", quantity: 6 }
];

function countThem() {
  var names_array = [];
  for (var i = 0; i < big_array.length; i++) {
    names_array.push( Object.assign({}, big_array[i]) );
  }

  function outerHolder(item_array) {
    if (item_array.length > 0) {
      var occurrences = [];
      var counter = 0;
      var bgarlen = item_array.length;
      item_array.sort(function(a, b) { return (a.name > b.name) ? 1 : ((b.name > a.name) ? -1 : 0); });

      function recursiveCounter() {
        occurrences.push(item_array[0]);
        item_array.splice(0, 1);
        var last_occurrence_element = occurrences.length - 1;
        var last_occurrence_entry = occurrences[last_occurrence_element].name;
        var occur_counter = 0;
        var quantity_counter = 0;
        for (var i = 0; i < occurrences.length; i++) {
          if (occurrences[i].name === last_occurrence_entry) {
            occur_counter = occur_counter + 1;
            if (occur_counter === 1) {
              quantity_counter = occurrences[i].quantity;
            } else {
              quantity_counter = quantity_counter + occurrences[i].quantity;
            }
          }
        }

        if (occur_counter > 1) {
          var current_match = occurrences.length - 2;
          occurrences[current_match].quantity = quantity_counter;
          occurrences.splice(last_occurrence_element, 1);
        }

        counter = counter + 1;

        if (counter < bgarlen) {
          recursiveCounter();
        }
      }

      recursiveCounter();

      return occurrences;
    }
  }
  alert(JSON.stringify(outerHolder(names_array)));
}
function countOcurrences(arr){
    return arr.reduce((aggregator, value, index, array) => {
      if(!aggregator[value]){
        return aggregator = {...aggregator, [value]: 1};  
      }else{
        return aggregator = {...aggregator, [value]:++aggregator[value]};
      }
    }, {})
}

您可以通过使用count函数扩展数组来简化此操作如果您熟悉它,它的工作原理类似于RubyArray#count

Array.prototype.count = function(obj){
  var count = this.length;
  if(typeof(obj) !== "undefined"){
    var array = this.slice(0), count = 0; // clone array and reset count
    for(i = 0; i < array.length; i++){
      if(array[i] == obj){ count++ }
    }
  }
  return count;
}

用法:

let array = ['a', 'b', 'd', 'a', 'c'];
array.count('a'); // => 2
array.count('b'); // => 1
array.count('e'); // => 0
array.count(); // => 5

要旨


编辑

然后,您可以使用来获取第一个数组,其中包含每个出现的项Array#filter

let occurred = [];
array.filter(function(item) {
  if (!occurred.includes(item)) {
    occurred.push(item);
    return true;
  }
}); // => ["a", "b", "d", "c"]

和第二个数组,包含出现的次数,使用Array#countinto Array#map

occurred.map(array.count.bind(array)); // => [2, 1, 1, 1]

另外,如果订单无关紧要,则可以将其作为键值对返回:

let occurrences = {}
occurred.forEach(function(item) { occurrences[item] = array.count(item) });
occurences; // => {2: 5, 4: 1, 5: 3, 9: 1}
本文地址:http://javascript.askforanswer.com/jisuanshuzuyuansudechuxiancishu-pinshuai.html
文章标签: ,   ,   ,  
版权声明:本文为原创文章,版权归 javascript 所有,欢迎分享本文,转载请保留出处!

文件下载

老薛主机终身7折优惠码boke112

上一篇:
下一篇:

评论已关闭!