Как я могу сохранить только элементы массива, которые соответствуют определенному условию?

У меня есть массив, и я хочу отфильтровать его, чтобы включить только элементы, которые соответствуют определенному условию. Это можно сделать в JavaScript?

Некоторые примеры:

[1, 2, 3, 4, 5, 6, 7, 8] // I only want [2, 4, 6, 8], i.e. the even numbers

["This", "is", "an", "array", "with", "several", "strings", "making", "up", "a", "sentence."] // I only want words with 2 or fewer letters: ["is", "an", "up", "a"]

[true, false, 4, 0, "abc", "", "0"] // Only keep truthy values: [true, 4, "abc", "0"]

3 ответа

Решение

Для этого вы можете использовать Array#filter() метод, введенный в ECMAScript5. Он поддерживается во всех браузерах, кроме IE8 и ниже, а также старых версий Firefox. Если по какой-либо причине вам необходимо поддерживать эти браузеры, вы можете использовать для этого метод polyfill.

filter() принимает функцию в качестве первого аргумента. Для каждого элемента массива вашей функции передаются три аргумента - значение текущего элемента, его индекс в массиве и сам массив. Если ваша функция возвращает true (или истинное значение, например, 1, "pizza", или же 42), этот пункт будет включен в результат. В противном случае это не так. filter() возвращает новый массив - ваш исходный массив останется неизменным. Это означает, что вам нужно где-то сохранить значение, иначе оно будет потеряно.

Теперь в примерах из вопроса:

var myNumbersArray = [1, 2, 3, 4, 5, 6, 7, 8];
console.log(myNumbersArray.filter(function(num){
  return !(num % 2); // keep numbers divisible by 2
}));
console.log(myNumbersArray); // see - it hasn't changed!

var myStringArray = ["This", "is", "an", "array", "with", "several", "strings", "making", "up", "a", "sentence."];
console.log(myStringArray.filter(function(str){
  return str.length < 3; // keep strings with length < 3
}));
console.log(myStringArray);

var myBoolArray = [true, false, 4, 0, "abc", "", "0"];
console.log(myBoolArray.filter(Boolean));
// wow, look at that trick!
console.log(myBoolArray);

И для полноты, пример, который также использует параметры индекса и массива: Удаление дубликатов из массива:

var myArray = [1,1,2,3,4,5,6,1,2,8,2,5,2,52,48,123,43,52];
console.log(myArray.filter(function(value, index, array) {
   return array.indexOf(value) === index;
}));

Для фильтрации записей, которые не являются строго массивами, и, следовательно, не имеют .filter Свойство на их прототипе, но все еще повторяемы (как document.getElementsByTagName), ты можешь использовать

Array.prototype.filter.call(collection, function filterFunction(el, index, collection) {
    ... 
});

Или стенография

[].filter.call(collection, function filterFunction(el, index, collection) {
    ...
});

Что касается объектов, которые не повторяются, но вы все же хотите отфильтровать свойства и получить массив ключей, которые проходят фильтрацию, вы можете комбинировать с Object.keys вот так:

var obj = { one: 1, two: 2, three: 3, four: 4 };
var filtered = Object.keys(obj).filter(function(key) {
    return obj[key] % 2 === 0;
}); //filtered == ['two', 'four']

Затем вы можете создать новый объект, содержащий эти свойства:

var filteredObj = filtered.reduce(function(newObj, currentKey) {
    newObj[currentKey] = obj[currentKey]; //Add the original value to the new object
    return newObj; //Return the new object to continue iteration
}, {}) // Begin iteration with a blank object

//filteredObj is now { two: 2, four: 4 }

Выше можно даже объединить в функцию!

function filterObject(obj, testCallback) {
    return Object.keys(obj).filter(function(key, index, array) {
        return testCallback(obj[key], index, array); //Call original filter but pass the property
    }).reduce(function(newObj, currentKey) {
        newObj[currentKey] = obj[currentKey]; //Add the original value to the new object
        return newObj; //Return the new object to continue iteration
    }, {}); // Begin iteration with a blank object
}

И используйте так:

var obj = { one: 1, two: 2, three: 3, four: 4 };
var filteredObj = filterObject(obj, function(el) { return el % 2 === 0 });

Более краткий ответ, следующий за ответом @Scimonster с использованием синтаксиса ES6:

 // even numbers
const even = [1, 2, 3, 4, 5, 6, 7, 8].filter(n => n%2 == 0);
// words with 2 or fewer letters
const words = ["This", "is", "an", "array", "with", "several", "strings", "making", "up", "a", "sentence."].filter(el => el.length <= 2);
// truable elements
const trues = [true, false, 4, 0, "abc", "", "0"].filter(v => v);

console.log(even);
console.log(words);
console.log(trues);

Другие вопросы по тегам