web-dev-qa-db-ja.com

配列要素の出現回数/頻度を数える

Javascriptでは、数値の初期配列を受け取り、その中の要素を数えようとしています。理想的には、結果は2つの新しい配列になります。最初の配列にはそれぞれ一意の要素が指定され、2番目の配列には各要素の出現回数が含まれます。しかし、私は出力のフォーマットについての提案を受け付けています。

たとえば、初期配列が次のようになっていたとします。

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

その後、2つの新しい配列が作成されます。最初のものはそれぞれのユニークな要素の名前を含みます:

5, 2, 9, 4

2番目の要素には、その要素が初期配列で発生した回数が含まれます。

3, 5, 1, 1

数5が最初の配列で3回発生するので、数2が5回発生し、9と4が1回表示されます。

私は多くの解決策を探しましたが、何もうまくいかないようで、私自身が試したすべてがばかげて複雑になってしまいました。任意の助けは大歓迎です!

ありがとう:)

181
Jack W

どうぞ:

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

ライブデモ:http://jsfiddle.net/simevidas/bnACW/

注意

これは Array.sort を使って元の入力配列の順序を変更します。

81
Šime Vidas

結果を保持するためにオブジェクトを使うことができます。

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

それで、今あなたのcountsオブジェクトは、そのカウントが特定の数に対するものであることをあなたに言うことができます:

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

メンバーの配列を取得したい場合は、単にkeys()関数を使用してください。

keys(counts); // returns ["5", "2", "9", "4"]
184
typeof
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}
78
adamse

下線またはlodashを使用している場合は、これが最も簡単な方法です。

_.countBy(array);

そのような:

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

他の人が指摘したように、結果に対して_.keys()関数と_.values()関数を実行すると、それぞれ一意の数値とその出現回数をそれぞれ取得できます。しかし、私の経験では、元のオブジェクトははるかに扱いやすいものです。

64
radicand

結果に2つの配列を使用しないでください。オブジェクトを使用してください。

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
}
51
mu is too short

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 コンストラクタに渡して、一意の値のコレクションを作成します。 スプレッドシンタックス はこれらの値を新しい配列に展開するので、mapを呼び出してこれを[value, count]ペアの2次元配列に変換できます。つまり、次のような構造になります。

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

新しい配列は、次に Map コンストラクタに渡され、 iterable オブジェクトになります。

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

Mapオブジェクトの素晴らしいところは、データ型を保持することです。つまり、aCount.get(5)3を返しますが、aCount.get("5")undefinedを返します。また、anyの値/型をキーとして機能させることもできます。これは、このソリューションでもオブジェクトの配列を処理できることを意味します。

function frequencies(/* {Array} */ a){
    return new Map([...new Set(a)].map(
        x => [x, a.filter(y => y === x).length]
    ));
}

let foo = { value: 'foo' },
    bar = { value: 'bar' },
    baz = { value: 'baz' };

let aNumbers = [5, 5, 5, 2, 2, 2, 2, 2, 9, 4],
    aObjects = [foo, bar, foo, foo, baz, bar];

frequencies(aNumbers).forEach((val, key) => console.log(key + ': ' + val));
frequencies(aObjects).forEach((val, key) => console.log(key.value + ': ' + val));
35
Emissary

これが、配列内で同じ値を持つ出現回数を数える最も簡単な方法だと思います。

var a = [true, false, false, false];
a.filter(function(value){
    return value === false;
}).length
29
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))
26
Vlad Bezden

あなたが単一のライナーを好むならば。

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

編集(6/12/2015):内側からの説明。 countMapは、Wordとその頻度をマッピングするマップです。これは、無名関数を見ることができます。減らすことは、最後の関数呼び出しの戻り値として渡されるすべての配列要素およびcountMapとして引数を使用して関数を適用することです。最後のパラメータ({})は、最初の関数呼び出しに対するcountMapのデフォルト値です。

20
rjalfa

ES6版はずっと単純化されるべきです(もう1つのラインソリューション)

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 }

単純なオブジェクトではなくマップで、さまざまな種類の要素を区別することができます。それ以外の場合は、すべて文字列に基づいてカウントされます。

14
William Leung

アンダースコアを使用している場合は、機能的なルートに進むことができます。

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)

そして2番目の配列は

_.values(results)

利用可能な場合、これのほとんどはデフォルトでネイティブのJavaScript関数になります。

デモ: http://jsfiddle.net/dAaUU/

8
jhnstn

答え of @ adamse@ pmandell (私が支持しています)に基づいて、ES6でそれをすることができます1行

  • 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},{})

));
6
ESL

このように、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();
alert(freqs[2]); //=> 5
// or
var freqs = '1,1,2,one,one,2,2,22,three,four,five,three,three,five'
             .split(',')
             .frequencies();
alert(freqs.three); //=> 3

あるいは、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;
  }
5
KooiInc

これは、目に優しく軽いものです。

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;
}
5
ElDoRado1239

だからここに私が最新のJavascript機能のいくつかでそれをする方法があります:

まず、配列を Map の数に減らします。

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

Mapを使うことで、あなたの最初の配列はどんなタイプのオブジェクトも含むことができ、カウントは正しいでしょう。 Mapがないと、いくつかの種類のオブジェクトはあなたに奇妙な数を与えるでしょう。違いの詳細については Map docs を参照してください。

すべての値がシンボル、数字、または文字列である場合、これはオブジェクトでも実行できます。

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またはオブジェクトを使用したり(オブジェクトとは異なり、マップは直接反復可能になったり)、2つの配列に変換することができます。

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)
5
Garrett Motzner

1行のES6ソリューション。オブジェクトをマップとして使用して非常に多くの回答がありますが、実際の Map を使用している人は誰もいません

const map = arr.reduce((acc, e) => acc.set(e, acc.get(e) + 1 || 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) + 1 || 1), new Map());

console.info(...map.keys())
console.info(...map.values())
console.info(...map.entries())
4
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};

それでも2配列が必要な場合は、answerのように使用できます。

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];
4
SoEzPz

ES6ソリューションでreduce(固定):

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

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

ラムダと私の解決策:

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へのリンク

2
Michal

これが最も簡単な解決策です。

const data = [5, 5, 5, 2, 2, 2, 2, 2, 9, 4];
let occurance_arr=[]; 
const aCount =  [...new Set(data)].map(x => {
   occurance_arr.Push(data.filter(y=> y==x).length)
});
console.log(occurance_arr);   //[3, 5, 1, 1]
1
Ankur

別の見方...

let array = [5, 5, 5, 2, 2, 2, 2, 2, 9, 4]
let count = 0
let finalResult = []
array.sort().map((e, index)=>{
    if(e==array[index+1]){
        count++
    } else {
        count++
        finalResult.Push([e+" => "+count])
        count = 0
    }
})
console.log(finalResult)

// output
// [ [ '2 => 5' ], [ '4 => 1' ], [ '5 => 3' ], [ '9 => 1' ] ]
1
Miguel Afonso

下記のコードをチェックしてください。

<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;
}
1
Aamir Afridi
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]);
}
0
Dilraj Singh

@Emissaryに彼の解決策の調整について尋ねた私のコメントに関して。私はそれを処理した方法を追加します。

let distinctArr = yourArray.filter((curElement, index, array) => array.findIndex(t =>    t.prop1=== curElement.prop1 && t.prop2 === curElement.prop2 && t.prop3=== curElement.prop3) === index);
let distinctWithCount = [...new Set(distinctArr)].map(function(element){element.prop4 = yourArray.filter(t =>    t.prop1=== element.prop1 && t.prop2 === element.prop2 && t.prop2=== element.prop2).length;

ここで行うことは、最初に重複を削除して配列(distinctArr)を保存し、次に元の配列(yourArray)にオブジェクトが複製された時間をカウントし、オカレンスの値を持つ4番目のプロパティを追加することです。

それがES6で作られているこの特定の解決策を必要としている人のために役立つことを願っています

0
sharon gur

count関数を使って配列を拡張することで、これをずっと簡単にすることができます。あなたがそれに精通しているなら、それはRailsのArray#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;
}

使用法:

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

出典(要旨)

0
zykadelic
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]};
      }
    }, {})
}
0
José Salgado

これは、オブジェクトの配列内の出現回数を数える方法です。また、最初の配列の内容を新しい配列内に配置して、元の配列の順序が乱れないように値をソートします。次に、再帰関数を使用して各要素を調べ、配列内の各オブジェクトの数量プロパティを数えます。

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)));
}
0
nate_js

ramda.jsを使用してこれを実行できる、はるかに優れた簡単な方法があります。 ここのサンプルコード

const ary = [5, 5, 5, 2, 2, 2, 2, 2, 9, 4]; R.countBy(r=> r)(ary) countByのドキュメントは documentation にあります

私はcodewarsに関する同様の問題を解決していて、私のために働く以下の解決策を考案しました。

これにより、配列内の整数の最大数とその整数自体が得られます。文字列配列にも適用できると思います。

文字列を正しくソートするには、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;
}
0
Varun Upadhyay

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)
0
Melchia

この質問は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;
0
rags2riches

フィルターで簡単

この例では、単純にcountを割り当てています。これは、探しているキーでフィルター処理された配列の長さです。

let array = [{name: "steve", age: 22}, {name: "bob", age: 30}]

let count = array.filter(obj => obj.name === obj.name).length

console.log(count)

jS Filitersの詳細はこちら https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter

0
Alex Wood

配列x、つまりx = ['boy','man','oldman','scout','pilot'];が要素の出現回数'man'であるとする

x.length - x.toString().split(',man,').toString().split(',').length ;