Неперехваченная ошибка типа — при объединении и удалении (объединении) дубликатов в массиве объектов

#javascript #arrays

#javascript #массивы

Вопрос:

У меня есть массив объектов, в котором каждый объект имеет много разных ключей, но наиболее важные показаны ниже…

 productArray = [{
  id: 123,
  name 'Sony TV',
  price: 500,
  stock: 123
},
{
  id: 127,
  name 'Sharp TV',
  price: 750,
  stock: 230
},
{
  id: 123,
  name 'Sony TV',
  price: 500,
  stock: 77
}]
  

Очевидно, что это намного больше (скажем, 100 продуктов)… теперь я хочу объединить все имеющиеся у меня дубликаты (например, продукт с именем «Sony TV» — так что в моем массиве объектов есть только одна запись, и уровни запасов объединяются, и я также хочу, чтобы была выбрана самая высокая цена. Я написал вложенный цикл, который проходит через массив объектов, затем во втором массиве проверяет, имеет ли элемент тот же идентификатор, если это так, я добавляю уровни запасов вместе, беру самую высокую цену, затем удаляю дубликат из вложенного цикла (поскольку элемент может появляться более двух раз, вфакт, некоторые элементы могут появляться 5 или 6 раз). Есть некоторые другие бизнес-правила, но они сейчас не важны. Это мой код цикла…

 for (i = 0; i < productArray.length; i  ) {

        // check if duplicate... second loop
        for (j = productArray.length - 1; j >= 0; j--) {

            if (productArray[i].id === productArray[j].id amp;amp; productArray[i].id !== undefined) {
                // overwrite, update and combine values... e.g
                console.log('We have a match with '    productArray[i].id);
                productArray[i].stock = productArray[i].stock   productArray[j].stock;
                // remove match item from second array
                productArray[j].splice(j, 1);
            }
        }
    }
  

Теперь я делаю что-то очень неправильное, как я понимаю Uncaught TypeError: undefined is not a function . Я почти уверен, что это происходит потому, что моя логика ошибочна, и я иду по этому неправильному пути. Может кто-нибудь, пожалуйста, предложить лучший способ сделать это или объяснить, почему моя логика выдает ошибку? Заранее большое спасибо.

Комментарии:

1. Вероятно, это связано с тем, что вы изменяете массив во время итерации по нему.

2. Я думал, что итерация вниз по второму массиву устранит эту проблему

Ответ №1:

Это происходит потому, что всякий раз, когда вы удаляете элемент из массива, и вы все еще запускаете второй цикл for и случай, когда i>length … попробуйте использовать это…

 if ( i < productArray.length amp;amp; productArray[i].id !== undefined amp;amp; productArray[i].id === productArray[j].id )
  

Вы проверяете, если productArray[i].id !== undefined только после проверки productArray[i].id === productArray[j].id , и поэтому, если i>arrayLength productArray[i].id вернет ошибку

Комментарии:

1. Я все еще получаю ту же ошибку? Возможно, для меня есть лучший способ найти дубликаты и выполнить поправки / вычисления, которые я изначально пробовал?

Ответ №2:

Не проще ли было бы использовать map для хранения повторяющихся элементов, а затем создать из него массив?

 var products = [{
    name: 'Sony TV',
    stock: 123
  },
  {
    name: 'Sharp TV',
    stock: 230
  },
  {
    name: 'Sony TV',
    stock: 77
  }];

var productsMap = {};

_.each(products, function (item) {
  if (!productsMap[item.name]) {
    productsMap[item.name] = item;
  } else {
    productsMap[item.name].stock  = item.stock;
  }
});

// map to array
var result = _.values(productsMap)
  

без подчеркивания:

 var productsMap = {};

for (var i = 0; i < products.length; i  ) {
  var item = products[i];
  if (!productsMap[item.name]) {
    productsMap[item.name] = item;
  } else {
    productsMap[item.name].stock  = item.stock;
  }
}

var result = [];
for (var name in productsMap) {
  result.push(productsMap[name]);
}
  

Комментарии:

1. Я не могу использовать подчеркивание!

2. «каждый» — это простое «для», «значения» также являются простой итерацией.

3. добавлена версия без подчеркивания

Ответ №3:

Вы пытаетесь вызвать .splice() что-то, что не является массивом. Кажется, вы хотите

  productArray.splice(j, 1);
  

вместо

  productArray[j].splice(j, 1);
  

Другая проблема заключается в том, что вы не проверяете, является ли найденный вами «дубликат» самим элементом. Таким образом, вы в основном очищаете весь массив, поскольку каждый элемент является дубликатом самого себя.

Я думаю, вы можете легко исправить это, изменив свой внутренний цикл, чтобы выполнять итерацию только до i-го элемента:

 for (j = productArray.length - 1; j > i; j--) {
  

Однако повторение массива в «обычном» порядке во внешнем цикле является еще одной проблемой. Просто выполните итерацию в обратном порядке в обоих циклах.

Комментарии:

1. Это отличное место.. однако теперь я получаю неперехваченную ошибку типа: не удается прочитать свойство ‘id’ неопределенного

2. @Mark так что просто замените порядок в if

3. @MarkSandman: Теперь это действительно может быть связано с мутацией массива внутри цикла. редактировать: проблема в том, что вы удаляете сам элемент, даже если он не является дубликатом. Вы могли бы проверить i !== j , однако, поскольку вы изменяете массив, i и j может произойти «рассинхронизация». Вероятно, лучшим решением является создание нового массива.