Ідіоматично знаходять кількість входжень даного значення в масиві

У мене є масив з повторюваними значеннями. Я хотів би знайти кількість входжень для будь-якого заданого значення.

Наприклад, якщо у мене є масив, визначений таким чином: var database = [2,2,4,2,6,4,7,8]; , я хочу знайти кількість входжень певне значення в масиві. Тобто програма повинна показати, що якщо у мене є 3 входження значення 2 , 1 виникнення значення 6 і так далі.

Який найбільш ідіоматичний/елегантний спосіб зробити це?

30

10 Відповіді

reduce is more appropriate here than filter as it doesn't build a temporary array just for counting.

<div class="snippet" data-lang="js" data-hide="false" data-console="true" data-babel="false"> <div class="snippet-code">

var dataset = [2,2,4,2,6,4,7,8];
var search = 2;

var count = dataset.reduce(function(n, val) {
    return n + (val === search);
}, 0);

console.log(count);
</div> </div>

Зауважте, що можна легко розширити, що для використання спеціального предиката відповідності, наприклад, для підрахунку об'єктів, які мають певну властивість:

<div class="snippet" data-lang="js" data-hide="false" data-console="true" data-babel="false"> <div class="snippet-code">

people = [
    {name: 'Mary', gender: 'girl'},
    {name: 'Paul', gender: 'boy'},
    {name: 'John', gender: 'boy'},
    {name: 'Lisa', gender: 'girl'},
    {name: 'Bill', gender: 'boy'},
    {name: 'Maklatura', gender: 'girl'}
]

var numBoys = people.reduce(function (n, person) {
    return n + (person.gender == 'boy');
}, 0);

console.log(numBoys);
</div> </div>

Підрахунок усіх елементів, тобто створення об'єкта, наприклад, {x: count of xs} , є складним у JavaScript, оскільки ключі об'єктів можуть бути лише рядками, тому ви не можете надійно підраховувати масив зі змішаними типами . Тим не менш, наступне просте рішення буде добре працювати в більшості випадків:

<div class="snippet" data-lang="js" data-hide="false" data-console="true" data-babel="false"> <div class="snippet-code">

count = function (ary, classifier) {
    classifier = classifier || String;
    return ary.reduce(function (counter, item) {
        var p = classifier(item);
        counter[p] = counter.hasOwnProperty(p) ? counter[p] + 1 : 1;
        return counter;
    }, {})
};

people = [
    {name: 'Mary', gender: 'girl'},
    {name: 'Paul', gender: 'boy'},
    {name: 'John', gender: 'boy'},
    {name: 'Lisa', gender: 'girl'},
    {name: 'Bill', gender: 'boy'},
    {name: 'Maklatura', gender: 'girl'}
];

// If you don't provide a `classifier` this simply counts different elements:

cc = count([1, 2, 2, 2, 3, 1]);
console.log(cc);

// With a `classifier` you can group elements by specific property:

countByGender = count(people, function (item) {
    return item.gender
});
console.log(countByGender);
</div> </div>

2017 оновлення

У ES6 ви використовуєте об'єкт Map для надійного підрахунку об'єктів довільних типів:

<div class="snippet" data-lang="js" data-hide="false" data-console="true" data-babel="false"> <div class="snippet-code">

class Counter extends Map {
    constructor(iter, key=null) {
        super();
        this.key = key || (x => x);
        for (let x of iter) {
            this.add(x);
        }
    }
    add(x) {
      x = this.key(x);
      this.set(x, (this.get(x) || 0) + 1);
    }
}

// again, with no classifier just count distinct elements

results = new Counter([1, 2, 3, 1, 2, 3, 1, 2, 2]);
for (let [number, times] of results.entries())
    console.log('%s occurs %s times', number, times);


// counting objects

people = [
    {name: 'Mary', gender: 'girl'},
    {name: 'John', gender: 'boy'},
    {name: 'Lisa', gender: 'girl'},
    {name: 'Bill', gender: 'boy'},
    {name: 'Maklatura', gender: 'girl'}
];


chessChampions = {
    2010: people[0],
    2012: people[0],
    2013: people[2],
    2014: people[0],
    2015: people[2],
};

results = new Counter(Object.values(chessChampions));
for (let [person, times] of results.entries())
    console.log('%s won %s times', person.name, times);

// you can also provide a classifier as in the above

byGender = new Counter(people, x => x.gender);
for (let g of ['boy', 'girl'])
   console.log("there are %s %ss", byGender.get(g), g);
</div> </div>
67
додано
@ thg435 Я спробував використати це і закінчив з невизначеним значенням ... а також, чи метод reduction зберігає масив? Я хотів би зберегти масив без змін.
додано Автор Shrey Gupta, джерело
@Bagavatu: опублікуйте свій код/​​скрипку. Ні, зменшення не змінює масив.
додано Автор georg, джерело

Newer browsers only due to using Array.filter

var dataset = [2,2,4,2,6,4,7,8];
var search = 2;
var occurrences = dataset.filter(function(val) {
    return val === search;
}).length;
console.log(occurrences);//3
11
додано
Або, коротше: occurrence = dataset.filter (v => v === пошук) .length
додано Автор Ninjakannon, джерело
array.filter(c => c === searchvalue).length;
9
додано

Ось один із способів одночасно відобразити ВСЕ :

var dataset = [2, 2, 4, 2, 6, 4, 7, 8];
var counts = {}, i, value;
for (i = 0; i < dataset.length; i++) {
    value = dataset[i];
    if (typeof counts[value] === "undefined") {
        counts[value] = 1;
    } else {
        counts[value]++;
    }
}
console.log(counts);
// Object {
//    2: 3,
//    4: 2,
//    6: 1,
//    7: 1,
//    8: 1
//}
7
додано

Використовуючи звичайний цикл, ви можете знайти послідовно та надійно:

const dataset = [2,2,4,2,6,4,7,8];

function getNumMatches(array, valToFind) {
    let numMatches = 0;
    for (let i = 0, j = array.length; i < j; i += 1) {
        if (array[i] === valToFind) {
            numMatches += 1;
        }
    }
    return numMatches;
}

alert(getNumMatches(dataset, 2));//should alert 3

DEMO: https://jsfiddle.net/a7q9k4uu/

Щоб зробити її більш загальною, функція може прийняти функцію предикатів зі спеціальною логікою (повертаючи true / false ), яка визначатиме остаточний рахунок. Наприклад:

const dataset = [2,2,4,2,6,4,7,8];

function getNumMatches(array, predicate) {
    let numMatches = 0;
    for (let i = 0, j = array.length; i < j; i += 1) {
        const current = array[i];
        if (predicate(current) === true) {
            numMatches += 1;
        }
    }
    return numMatches;
}

const numFound = getNumMatches(dataset, (item) => {
    return item === 2;
});

alert(numFound);//should alert 3

DEMO: https://jsfiddle.net/57en9nar/1/

6
додано
+1 Для перенесення в семантично зрозумілу і читається функцію. Хоча я б назвав його getNumMatches або getNumOccurrences . findOccurrences звучить так, ніби ви намагаєтеся повернути самі події (масив), а не скільки їх (число).
додано Автор Adam Zerner, джерело
Крім того, як згадували інші, ви можете передати функцію предикатів замість значення, щоб перевірити відповідність. Демонстраційна версія:
додано Автор Adam Zerner, джерело
@AdamZerner Погоджено, спасибі за вхід. Оновлено з Вашими рекомендаціями
додано Автор Ian, джерело
var dataset = [2,2,4,2,6,4,7,8], count = {}

dataset.forEach(function(el){
    count[el] = count[el] + 1 || 1
});

console.log(count)

//  {
//    2: 3,
//    4: 2,
//    6: 1,
//    7: 1,
//    8: 1
//  }
4
додано
Він перевіряє кожну петлю, якщо ключ вже існує. Якщо так, то збільшується поточне значення. Якщо не вставити 1 для цього ключа.
додано Автор TdoubleG, джерело

Ви можете скористатися методом array.reduce (метод callback [ initialValue]) в JavaScript 1.8

var dataset = [2,2,4,2,6,4,7,8],
    dataWithCount = dataset.reduce( function( o , v ) {

        if ( ! o[ v ] ) {
            o[ v ] = 1 ;  
        }  else {
            o[ v ] = o[ v ] + 1;
        }      

        return o ;    

    }, {} );

// print data with count.
for( var i in  dataWithCount ){
     console.log( i + 'occured ' + dataWithCount[i] + 'times ' ); 
}

// find one number
var search = 2,
    count = dataWithCount[ search ] || 0;
3
додано

Ви можете підрахувати всі елементи в масиві, в одному рядку, використовуючи зменшення.

[].reduce((a,b) => (a[b] = a[b] + 1 || 1) && a, {})

Це дасть об'єкт, ключі якого є різними елементами в масиві, а значення - кількість випадків виникнення елементів в масиві. Потім можна отримати доступ до одного або декількох підрахунків, звернувшись до відповідної клавіші на об'єкті.

Наприклад, якщо ви перетворили вищезгадану функцію під назвою count() :

function count(arr) {
  return arr.reduce((a,b) => (a[b] = a[b] + 1 || 1) && a, {})
}

count(['example'])         //{ example: 1 }
count([2,2,4,2,6,4,7,8])[2]//3
2
додано

Мені було доцільніше знайти список об'єктів за допомогою ключа для того, що підраховується, і ключа для підрахунку:

const data = [2,2,4,2,6,4,7,8]
let counted = []
for (var c of data) {
  const alreadyCounted = counted.map(c => c.name)
  if (alreadyCounted.includes(c)) {
    counted[alreadyCounted.indexOf(c)].count += 1
  } else {
    counted.push({ 'name': c, 'count': 1})
  }
}
console.log(counted)

яка повертається:

[ { name: 2, count: 3 },
  { name: 4, count: 2 },
  { name: 6, count: 1 },
  { name: 7, count: 1 },
  { name: 8, count: 1 } ]

Це не найчистіший метод, і якщо хтось знає, як досягти того самого результату з reduction , дайте мені знати. Тим не менш, це робить результат, який досить легко працювати.

0
додано

По-перше, ви можете скористатися методом Brute Force Solution за допомогою функції Linear Search.

public int LinearSearchcount(int[] A, int data){
  int count=0;
  for(int i=0;i

Однак, для того, щоб піти з цим, ми отримуємо складність часу як O (n).

0
додано
ІТ КПІ - JavaScript
ІТ КПІ - JavaScript
504 учасників

співтовариство javascript розробників в Telegram