Удаление элементов с помощью Array.map в JavaScript

Я хотел бы отфильтровать массив элементов с помощью map()функции. Вот фрагмент кода:

var filteredItems = items.map(function(item)
{
    if( ...some condition... )
    {
        return item;
    }
});

Проблема в том, что отфильтрованные элементы все еще используют пространство в массиве, и я хотел бы полностью стереть их.

Есть идеи?

РЕДАКТИРОВАТЬ: Спасибо, я забыл о том filter(), что я хотел на самом деле filter()тогда map().

РЕДАКТИРОВАТЬ 2: Спасибо за указание map()и filter()не реализованы во всех браузерах, хотя мой конкретный код не был предназначен для запуска в браузере.

12.08.2008 22:21:30
Можете ли вы объяснить, почему 2 итерации хуже, чем 1? Я имею в виду, 2 * O (n) для меня эквивалентно O (2 * n) ...
Vincent Robert 9.06.2016 10:07:26
8 ОТВЕТОВ
РЕШЕНИЕ

Вы должны использовать filterметод, а не карту, если вы не хотите изменять элементы в массиве, в дополнение к фильтрации.

например.

var filteredItems = items.filter(function(item)
{
    return ...some condition...;
});

[Редактировать: Конечно, вы всегда можете сделать, sourceArray.filter(...).map(...)чтобы фильтровать и изменять]

94
12.08.2008 22:38:28
mapне видоизменяется
Thank you 23.09.2016 16:38:33
Но вы можете мутировать в map.
Crazywako 8.05.2017 12:54:06
Осторожно с этим: поскольку JS передает ссылку, когда вы изменяете что-то с помощью map, он меняет объект, но, когда MDN стоит, maps возвращает мутированный массив.
alexOtano 28.09.2019 13:38:20
На вопрос не спрашивали, как отфильтровать, на вопрос спрашивали, как удалить на карте
Dazzle 16.01.2020 16:08:11

Это не то, что делает карта. Вы действительно хотите Array.filter . Или, если вы действительно хотите удалить элементы из исходного списка, вам обязательно нужно сделать это с помощью цикла for.

10
12.08.2008 22:33:45

Однако вы должны заметить, что 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;
    };
}

И, таким образом, вы можете создать прототип любого метода, который вам может понадобиться.

2
7.02.2016 18:23:25
Если вы действительно намереваетесь заполнить этот метод полифилом, пожалуйста, используйте правильный полифил, или еще лучше такую ​​библиотеку, как Modernizr . В противном случае вы, вероятно, столкнетесь с запутанными ошибками в неизвестных браузерах, которые вы не поймете, пока они не будут в работе слишком долго.
Kyle Baker 25.04.2018 21:24:40

Метод фильтра массива

var arr = [1, 2, 3]

// ES5 syntax
arr = arr.filter(function(item){ return item != 3 })

// ES2015 syntax
arr = arr.filter(item => item != 3)

console.log( arr )

5
25.06.2019 07:10:31
Вы также можете сделатьvar arr = [1,2,"xxx", "yyy"]; arr = arr.filter(function(e){ return e!="xxx" }) console.log(arr)
jack blank 2.12.2015 09:15:49
Вы вернулись 4 года спустя, чтобы добавить огромный текст? минус один
Thank you 25.06.2019 13:37:57
@ user633183 Кого ты имеешь в виду? какой "огромный текст"? Ваш комментарий неясен. Вы уверены, что комментируете в правильном месте ...?
vsync 25.06.2019 14:39:36

Я написал ответ некоторое время назад, и мое мнение изменилось. Я рекомендую ознакомиться с моим постом в блоге, который расширяет эту тему и объясняет ее более детально и нюансивно, а также строит понимание по частям. В конце также приводится сравнение JSperf, исходя из соображений скорости.

Tl; dr заключается в следующем: чтобы выполнить то, что вы просите (фильтрация и отображение в пределах одного вызова функции), вы должны использоватьArray.reduce() . Тем не менее, более удобным для чтения и (менее важно) , как правило , значительно быстрее 2 подход заключается в использовании только фильтра и карты соединены друг с другом:

[1,2,3].filter(num => num > 2).map(num => num * 2)

Далее следует описание того, как Array.reduce()работает и как его можно использовать для выполнения фильтрации и сопоставления за одну итерацию. Если это слишком сжато, я настоятельно рекомендую посмотреть пост в блоге, связанный выше, который является более дружественным вступлением с ясными примерами и прогрессом.

Вы даете уменьшить аргумент, который является (обычно анонимной) функцией.

Эта анонимная функция принимает два параметра - один (например, анонимные функции, передаваемые в map / filter / forEach) - это итератор, с которым нужно работать. Однако для анонимной функции передается еще один аргумент, заключающийся в том, что эти функции не принимаются, и это значение, которое будет передаваться между вызовами функций, часто называемое памяткой .

Обратите внимание, что хотя Array.filter () принимает только один аргумент (функцию), Array.reduce () также принимает важный (хотя и необязательный) второй аргумент: начальное значение для memo, которое будет передано в эту анонимную функцию в качестве ее первый аргумент, а затем может быть видоизменен и передан между вызовами функций. (Если он не указан, то по умолчанию «memo» в первом вызове анонимной функции будет первым итератором, а аргумент «итератора» фактически будет вторым значением в массиве)

В нашем случае мы передадим пустой массив для запуска, а затем выберем, вставлять нашего итератора в наш массив или нет, основываясь на нашей функции - это процесс фильтрации.

Наконец, мы будем возвращать наш «массив в процессе» при каждом вызове анонимной функции, а Reduce примет это возвращаемое значение и передаст его в качестве аргумента (называемого memo) следующему вызову функции.

Это позволяет фильтровать и отображать в одну итерацию, сокращая количество необходимых итераций вдвое - просто выполняя вдвое больше работы за каждую итерацию, тем не менее, ничего не сохраняется, кроме вызовов функций, которые не так дороги в 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.log(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]);
    }

    // after we've compressed the array into a single value,
    // we return it.
    return memo;
}

Реальная реализация позволяет получить доступ к таким вещам, как, например, индекс, но я надеюсь, что это поможет вам получить несложное представление о его сути.

37
18.04.2020 14:09:51
блестящий! Я давно хотел сделать что-то подобное. Решил попытаться разобраться в приятном и естественном javascript!
jemiloii 13.09.2017 14:41:25
Еще одна полезность reduceзаключается в том, что в отличие от filter+ map, обратному вызову может быть передан индексный аргумент, который является индексом исходного массива, а не индекса отфильтрованного.
congusbongus 16.04.2018 06:24:56
Похоже, что в таком случае, тебе было бы лучше сделать, mapа потом filter. Мне трудно представить себе случай, когда мне понадобился бы такой доступ, который не был бы плохим дизайном.
Kyle Baker 9.12.2018 02:41:11
@KyleBaker Ссылка на ваш блог отправляется на страницу не найдена. Можете ли вы обновить ссылку? Спасибо!
Tim Philip 8.01.2020 17:15:51
@TimPhilip, обновлено. Спасибо.
Kyle Baker 30.01.2020 23:03:33

Следующее утверждение очищает объект с помощью функции карты.

var arraytoclean = [{v:65, toberemoved:"gronf"}, {v:12, toberemoved:null}, {v:4}];
arraytoclean.map((x,i)=>x.toberemoved=undefined);
console.dir(arraytoclean);
0
7.10.2019 15:12:12

Я только что написал пересечение массива, который правильно обрабатывает также дубликаты

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.log;
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' ]

0
15.11.2019 15:29:08

Сначала вы можете использовать карту и с цепочкой вы можете использовать фильтр

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;
            }
        });
0
20.04.2020 17:15:22