#javascript #arrays #sorting #reduce
Вопрос:
У меня есть массив объектов следующим образом.
const arr = [
{
categoryId: "I01",
categoryName: "Category_one",
price: 100
},
{
categoryId: "I02",
categoryName: "Category_two",
price: 200
},
{
categoryId: "I03",
categoryName: "Category_three",
price: 300
},
{
categoryId: "I02",
categoryName: "Category_two",
price: 210
},
{
categoryId: "I03",
categoryName: "Category_three",
price: 310
}
]
И я работаю над тем, чтобы получить следующий результат. Это похоже на фильтрацию всего массива по категориям.
arr2 = [
{
id: 0,
categoryId: "I01",
categoryName: "Category_one",
minimum_price: 100,
count: 1
},
{
id: 1,
categoryId: "I02",
categoryName: "Category_two",
minimum_price: 200,
count: 2
},
{
id: 2,
categoryId: "I03",
categoryName: "Category_three",
minimum_price: 300,
count: 2
},
]
Я создал результат до уровня ниже
const resArr = [];
arr.forEach((item) => {
let i = resArr.findIndex(x => x.categoryId == item.categoryId);
if (i <= -1) {
resArr.push({ categoryId: item.categoryId, categoryName: item.categoryName });
}
});
resArr.forEach((o, i) => o.id = i);
И получил такой результат,
res = [
{
id: 0,
categoryId: "I01",
categoryName: "Category_one"
},
{
id: 1,
categoryId: "I02",
categoryName: "Category_two"
},
{
id: 2,
categoryId: "I03",
categoryName: "Category_three"
},
]
Мне нужно иметь значение minimum_price и значения количества. высоко ценю ваши предложения.
Ответ №1:
Вы можете использовать Array.prototype.reduce вместе с Object.values:
let id = -1;
// Even though we're reducing to an object, Object.values will
// extract the result to an array.
const result = Object.values(arr.reduce(({
categoryId,
categoryName,
price,
}, acc) => {
// If we don't already have something from that
// category, make a new entry in the hash
if (!(categoryId in acc)) acc[categoryId] = {
categoryId,
categoryName,
minPrice: price,
id: id , // increment the id
count: 0,
};
// Increase the count for that category by 1
acc[categoryId].count = 1;
// Set new minimum price if applicable
if (acc[categoryId].price > price) acc[categoryId].price = price;
// return the accumulator
return acc;
}, {}));
Комментарии:
1. Привет @Джаред Смит, я сверился со своими данными, но не смог получить ожидаемый результат с вашим ответом.
Ответ №2:
Я бы предложил это:
во-первых, примените id
поле:
arr.map(item=>({...item, id: Number(item.categoryId.slice(1))}))
И превратите его в (эффективно) Map<int, Category>
, вы можете использовать либо a Array
, либо a Map
, но вы должны знать, что это может быть не тот конечный массив, который вам нужен, потому что он может быть разреженным.
(и вы можете объединить первый шаг с этим):
const map = [];
for(const item of arr) {
const id = Number(item.categoryId.slice(1))
if(!map[id]) {
map[id] = {
id,
categoryId: item.categoryId,
categoryName: item.categoryName,
minimum_price: item.price,
count: 1
}
} else {
map[id].count = 1
map[id].minimum_price = Math.min(map[id].minimum_price, item.price)
}
}
И сделайте его конечным массивом, который вы хотите. Вы можете просто отфильтровать пустые слоты:
return map.filter(Boolean)
И я бы настоятельно рекомендовал вам id
придерживаться categoryId
этого . Наличие sth может сбивать с толку. Нравится {id: 0, categoryId: 'I01'}
.
И это то, что вы получите (JSON-строка):
[{"id":1,"categoryId":"I01","categoryName":"Category_one","minimum_price":100,"count":1},{"id":2,"categoryId":"I02","categoryName":"Category_two","minimum_price":200,"count":2},{"id":3,"categoryId":"I03","categoryName":"Category_three","minimum_price":300,"count":2}]
можете ли вы обновить свой ответ, если «идентификатор категории» не содержит никакого целого числа
Это зависит от того, хотите ли вы по-прежнему иметь значимое id
поле. Если нет, то карта должна быть Map<string, Category>
изображением (или объектом).:
const map = {};
for(const item of arr) {
if(!map[item.categoryId]) {
map[item.categoryId] = {
categoryId: item.categoryId,
categoryName: item.categoryName,
minimum_price: item.price,
count: 1
}
} else {
map[item.categoryId].count = 1
map[item.categoryId].minimum_price = Math.min(map[id].minimum_price, item.price)
}
}
И вам нужно будет превратить карту в массив, что может быть сделано Object.keys
, Object.values
Object.entries
, или for...in
циклом:
Object.values(map)
И примените это id
поле, если оно вам все еще нужно:
Object.values(map).map((v, id) => ({...v, id}))
Или, если вам нужно содержательное id
поле,
Вам нужно будет найти способ каким-то образом отобразить идентификатор категории в целое число.
Комментарии:
1. Привет, @Yongjian Wang, Ответ вполне одобрительный, но можете ли вы обновить свой ответ, если «Идентификатор категории» не содержит никакого целого числа.