Я хотел бы отфильтровать массив элементов с помощью функции map(). Вот фрагмент кода:
var filteredItems = items.map(function(item)
{
if ( ...some condition... )
{
return item;
}
});
Проблема в том, что отфильтрованные элементы по-прежнему используют пространство в массиве, и я хотел бы полностью их стереть.
Любая идея?
Обновлено: Спасибо, я забыл о filter(), то, что я хотел, на самом деле filter(), а затем map().
EDIT2: Спасибо, что указали, что map() и filter() не реализованы во всех браузерах, хотя мой конкретный код не предназначен для запуска в браузере.
Часто бывает полезно фильтровать и отображать в одной функции не по соображениям производительности, а, скорее, для уменьшения дублирования кода. Фактически, в Swift это встроено с функцией compactMap. См. этот ответ для получения дополнительной информации.



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Вам следует использовать метод filter, а не карту, если вы не хотите изменять элементы в массиве в дополнение к фильтрации.
например.
var filteredItems = items.filter(function(item)
{
return ...some condition...;
});
[Edit: Конечно, вы всегда можете использовать sourceArray.filter(...).map(...) как для фильтрации, так и для изменения]
map не мутирует
Но вы можете мутировать в map.
Будьте осторожны с этим: поскольку JS передает ссылку, когда вы что-то мутируете с помощью map, он изменяет объект, но, как стоит MDN, maps возвращает мутированный массив.
Вопрос не задал как фильтровать, задал вопрос как удалить на карте
@alexOtano Нет, карта не мутирует и не возвращает измененный массив. Он возвращает новый массив. например, x=[1,2,3];y = x.map(z => z*2);console.info(x,y);
Но можете ли вы изменить некоторые И удалить некоторые с помощью .map?
Я бы действительно рекомендовал сделать карту и фильтр тогда. См. этот ответ для получения дополнительной информации.
Однако вы должны отметить, что Array.filter поддерживается не всеми браузерами, поэтому вы должны создать прототип:
//This prototype is provided by the Mozilla foundation and
//is distributed under the MIT license.
//http://www.ibiblio.org/pub/Linux/LICENSES/mit.license
if (!Array.prototype.filter)
{
Array.prototype.filter = function(fun /*, thisp*/)
{
var len = this.length;
if (typeof fun != "function")
throw new TypeError();
var res = new Array();
var thisp = arguments[1];
for (var i = 0; i < len; i++)
{
if (i in this)
{
var val = this[i]; // in case fun mutates this
if (fun.call(thisp, val, i, this))
res.push(val);
}
}
return res;
};
}
Таким образом, вы можете создать прототип любого метода, который вам может понадобиться.
Если вы действительно собираетесь использовать этот метод полифилла, используйте подходящий полифилл или, еще лучше, библиотеку типа Modernizr. В противном случае вы, вероятно, столкнетесь с непонятными ошибками в малоизвестных браузерах, о которых вы не заметите, пока они не проработают слишком долго.
var arr = [1, 2, 3]
// ES5 syntax
arr = arr.filter(function(item){ return item != 3 })
// ES2015 syntax
arr = arr.filter(item => item != 3)
console.info( arr )вы также можете сделать var arr = [1,2,"xxx", "yyy"]; arr = arr.filter(function(e){ return e! = "xxx" }) console.info(arr)
Вы вернулись через 4 года, чтобы добавить огромный текст? минус один
@ user633183 Кого вы имеете в виду? что за "огромный текст"? Ваш комментарий неясен. Вы уверены, что комментируете нужное место ...?
Вдохновленный написанием этого ответа, я позже расширил и написал сообщение в блоге, в котором подробно рассказывалось об этом. Я рекомендую проверяя это, если вы хотите глубже понять, как думать об этой проблеме - я пытаюсь объяснить ее по частям, а также в конце привожу сравнение JSperf, не обращая внимания на соображения скорости.
Тем не менее, Это tl; dr:
Чтобы выполнить то, что вы просите (фильтрация и сопоставление в одном вызове функции), вы должны использовать Array.reduce().
Однако подход более читаемыйи (что менее важно) обычно значительно быстрее2 заключается в том, чтобы просто использовать объединенные вместе фильтр и карту:
[1,2,3].filter(num => num > 2).map(num => num * 2)
Далее следует описание того, как работает Array.reduce(), и как его можно использовать для выполнения фильтрации и сопоставления за одну итерацию. Опять же, если это слишком сжато, я настоятельно рекомендую просмотреть сообщение в блоге, указанное выше, которое является гораздо более дружелюбным вступлением с четкими примерами и прогрессом.
Вы даете reduce аргумент, который является (обычно анонимной) функцией.
Эта анонимная функция принимает два параметра - один (например, анонимные функции, переданные в map / filter / forEach) - это итерация, над которой нужно работать. Однако есть еще один аргумент для анонимной функции, переданной для уменьшения, который эти функции не принимают, и это значение, которое будет передаваться между вызовами функций, часто называемое памятка.
Обратите внимание, что в то время как Array.filter () принимает только один аргумент (функцию), Array.reduce () также принимает важный (хотя и необязательный) второй аргумент: начальное значение для 'memo', которое будет передано этой анонимной функции в качестве ее первый аргумент и впоследствии может быть изменен и передан между вызовами функций. (Если он не указан, то «memo» в первом вызове анонимной функции по умолчанию будет первым итератором, а аргумент «итерация» будет фактически вторым значением в массиве)
В нашем случае мы передадим пустой массив для запуска, а затем выберем, вставлять ли нашего итератора в наш массив или нет, в зависимости от нашей функции - это процесс фильтрации.
Наконец, мы возвращаем наш «массив в процессе выполнения» при каждом вызове анонимной функции, а reduce примет это возвращаемое значение и передаст его в качестве аргумента (называемого памяткой) своему следующему вызову функции.
Это позволяет выполнять фильтрацию и отображение за одну итерацию, сокращая количество требуемых итераций вдвое - просто делая в два раза больше работы на каждой итерации, поэтому на самом деле ничего не сохраняется, кроме вызовов функций, которые не так дороги в javascript. .
Для более полного объяснения обратитесь к документации MDN (или к моему сообщению, указанному в начале этого ответа).
Базовый пример вызова Reduce:
let array = [1,2,3];
const initialMemo = [];
array = array.reduce((memo, iteratee) => {
// if condition is our filter
if (iteratee > 1) {
// what happens inside the filter is the map
memo.push(iteratee * 2);
}
// this return value will be passed in as the 'memo' argument
// to the next call of this function, and this function will have
// every element passed into it at some point.
return memo;
}, initialMemo)
console.info(array) // [4,6], equivalent to [(2 * 2), (3 * 2)]
более емкая версия:
[1,2,3].reduce((memo, value) => value > 1 ? memo.concat(value * 2) : memo, [])
Обратите внимание, что первая итерация была не больше единицы и поэтому была отфильтрована. Также обратите внимание на initialMemo, названный просто для того, чтобы прояснить его существование и привлечь к нему внимание. И снова он передается как «памятка» при первом вызове анонимной функции, а затем возвращаемое значение анонимной функции передается в качестве аргумента «памятка» следующей функции.
Другой пример классического варианта использования memo - это возврат наименьшего или наибольшего числа в массиве. Пример:
[7,4,1,99,57,2,1,100].reduce((memo, val) => memo > val ? memo : val)
// ^this would return the largest number in the list.
Пример того, как написать свою собственную функцию уменьшения (я нахожу, это часто помогает понять подобные функции):
test_arr = [];
// we accept an anonymous function, and an optional 'initial memo' value.
test_arr.my_reducer = function(reduceFunc, initialMemo) {
// if we did not pass in a second argument, then our first memo value
// will be whatever is in index zero. (Otherwise, it will
// be that second argument.)
const initialMemoIsIndexZero = arguments.length < 2;
// here we use that logic to set the memo value accordingly.
let memo = initialMemoIsIndexZero ? this[0] : initialMemo;
// here we use that same boolean to decide whether the first
// value we pass in as iteratee is either the first or second
// element
const initialIteratee = initialMemoIsIndexZero ? 1 : 0;
for (var i = initialIteratee; i < this.length; i++) {
// memo is either the argument passed in above, or the
// first item in the list. initialIteratee is either the
// first item in the list, or the second item in the list.
memo = reduceFunc(memo, this[i]);
// or, more technically complete, give access to base array
// and index to the reducer as well:
// memo = reduceFunc(memo, this[i], i, this);
}
// after we've compressed the array into a single value,
// we return it.
return memo;
}
Реальная реализация позволяет получить доступ, например, к таким вещам, как индекс, но я надеюсь, что это поможет вам легко понять его суть.
молодец! Я много лет хотел сделать что-то подобное. Решил попробовать придумать красивый и хороший, и ничего себе, естественный javascript!
Еще одна полезность reduce заключается в том, что, в отличие от filter + map, обратному вызову может быть передан аргумент индекса, который является индексом исходного массива, а не отфильтрованного.
@KyleBaker Ссылка на ваше сообщение в блоге ведет на ненайденную страницу. Не могли бы вы обновить ссылку? Спасибо!
следующий оператор очищает объект с помощью функции карты.
var arraytoclean = [{v:65, toberemoved:"gronf"}, {v:12, toberemoved:null}, {v:4}];
arraytoclean.map((x,i)=>x.toberemoved=undefined);
console.dir(arraytoclean);
Я просто написал пересечение массивов, которое правильно обрабатывает также дубликаты
https://gist.github.com/gkucmierz/8ee04544fa842411f7553ef66ac2fcf0
// array intersection that correctly handles also duplicates
const intersection = (a1, a2) => {
const cnt = new Map();
a2.map(el => cnt[el] = el in cnt ? cnt[el] + 1 : 1);
return a1.filter(el => el in cnt && 0 < cnt[el]--);
};
const l = console.info;
l(intersection('1234'.split``, '3456'.split``)); // [ '3', '4' ]
l(intersection('12344'.split``, '3456'.split``)); // [ '3', '4' ]
l(intersection('1234'.split``, '33456'.split``)); // [ '3', '4' ]
l(intersection('12334'.split``, '33456'.split``)); // [ '3', '3', '4' ]Сначала вы можете использовать карту, а с цепочкой вы можете использовать фильтр
state.map(item => {
if (item.id === action.item.id){
return {
id : action.item.id,
name : item.name,
price: item.price,
quantity : item.quantity-1
}
}else{
return item;
}
}).filter(item => {
if (item.quantity <= 0){
return false;
}else{
return true;
}
});
TL; DR: используйте map (возвращая undefined при необходимости) и тогдаfilter.
Во-первых, я считаю, что функция карта + фильтр полезна, поскольку вы не хотите повторять вычисления в обоих. Первоначально Swift называл эту функцию flatMap, но затем переименовал ее в compactMap.
Например, если у нас нет функции compactMap, мы можем получить дважды определение computation:
let array = [1, 2, 3, 4, 5, 6, 7, 8];
let mapped = array
.filter(x => {
let computation = x / 2 + 1;
let isIncluded = computation % 2 === 0;
return isIncluded;
})
.map(x => {
let computation = x / 2 + 1;
return `${x} is included because ${computation} is even`
})
// Output: [2 is included because 2 is even, 6 is included because 4 is even]
Таким образом, compactMap был бы полезен для уменьшения дублирования кода.
Очень простой способ сделать что-то похожее на compactMap:
undefined.undefined.Это, конечно, зависит от того, что вам никогда не нужно будет возвращать неопределенные значения как часть вашей исходной функции карты.
Пример:
let array = [1, 2, 3, 4, 5, 6, 7, 8];
let mapped = array
.map(x => {
let computation = x / 2 + 1;
let isIncluded = computation % 2 === 0;
if (isIncluded) {
return `${x} is included because ${computation} is even`
} else {
return undefined
}
})
.filter(x => typeof x !== "undefined")
или вы можете просто использовать сокращение, чтобы предотвратить повторные вычисления.
Не могли бы вы пояснить, почему 2 итерации хуже 1? Я имею в виду, что 2 * O (n) для меня эквивалентно O (2 * n) ...