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

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

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

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

Любая идея?

Обновлено: Спасибо, я забыл о filter(), то, что я хотел, на самом деле filter(), а затем map().

EDIT2: Спасибо, что указали, что map() и filter() не реализованы во всех браузерах, хотя мой конкретный код не предназначен для запуска в браузере.

Не могли бы вы пояснить, почему 2 итерации хуже 1? Я имею в виду, что 2 * O (n) для меня эквивалентно O (2 * n) ...

Vincent Robert 09.06.2016 13:07

Часто бывает полезно фильтровать и отображать в одной функции не по соображениям производительности, а, скорее, для уменьшения дублирования кода. Фактически, в Swift это встроено с функцией compactMap. См. этот ответ для получения дополнительной информации.

Senseful 19.02.2021 21:16
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
99
2
110 327
9
Перейти к ответу Данный вопрос помечен как решенный

Ответы 9

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

Ответ принят как подходящий

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

например.

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

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

map не мутирует

Thank you 23.09.2016 19:38

Но вы можете мутировать в map.

Crazywako 08.05.2017 15:54

Будьте осторожны с этим: поскольку JS передает ссылку, когда вы что-то мутируете с помощью map, он изменяет объект, но, как стоит MDN, maps возвращает мутированный массив.

alexOtano 28.09.2019 16:38

Вопрос не задал как фильтровать, задал вопрос как удалить на карте

Dazzle 16.01.2020 19:08

@alexOtano Нет, карта не мутирует и не возвращает измененный массив. Он возвращает новый массив. например, x=[1,2,3];y = x.map(z => z*2);console.info(x,y);

Kyle Baker 16.05.2020 06:13

Но можете ли вы изменить некоторые И удалить некоторые с помощью .map?

trainoasis 05.01.2021 12:10

Я бы действительно рекомендовал сделать карту и фильтр тогда. См. этот ответ для получения дополнительной информации.

Senseful 19.02.2021 21:11

Однако вы должны отметить, что 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. В противном случае вы, вероятно, столкнетесь с непонятными ошибками в малоизвестных браузерах, о которых вы не заметите, пока они не проработают слишком долго.

Kyle Baker 26.04.2018 00:24

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

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)

jack blank 02.12.2015 12:15

Вы вернулись через 4 года, чтобы добавить огромный текст? минус один

Thank you 25.06.2019 16:37

@ user633183 Кого вы имеете в виду? что за "огромный текст"? Ваш комментарий неясен. Вы уверены, что комментируете нужное место ...?

vsync 25.06.2019 17:39

Вдохновленный написанием этого ответа, я позже расширил и написал сообщение в блоге, в котором подробно рассказывалось об этом. Я рекомендую проверяя это, если вы хотите глубже понять, как думать об этой проблеме - я пытаюсь объяснить ее по частям, а также в конце привожу сравнение 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!

jemiloii 13.09.2017 17:41

Еще одна полезность reduce заключается в том, что, в отличие от filter + map, обратному вызову может быть передан аргумент индекса, который является индексом исходного массива, а не отфильтрованного.

congusbongus 16.04.2018 09:24

@KyleBaker Ссылка на ваше сообщение в блоге ведет на ненайденную страницу. Не могли бы вы обновить ссылку? Спасибо!

Tim Philip 08.01.2020 20:15

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

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:

  1. Карта на реальных ценностях или undefined.
  2. Отфильтруйте все значения 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")

или вы можете просто использовать сокращение, чтобы предотвратить повторные вычисления.

Kyle Baker 02.03.2021 04:54

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