#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
может произойти «рассинхронизация». Вероятно, лучшим решением является создание нового массива.