我有一个这样的收藏集:
const data = [
{index: 1, number: 's1', uniqId: '123', city: 'LA'},
{index: 2, number: 's2', uniqId: '321', city: 'NY'},
{index: 3, number: 's3', uniqId: '123', city: 'LA'},
{index: 4, number: 's4', uniqId: '111', city: 'TX'},
{index: 5, number: 's5', uniqId: '321', city: 'NY'}
]
我希望将其分组以得到以下结果:
const data = [
{index: 1, numbers: ['s1', 's3'], uniqId: '123', city: 'LA'},
{index: 2, numbers: ['s2', 's5'], uniqId: '321', city: 'NY'},
{index: 3, number: 's4', uniqId: '111', city: 'TX'},
]
我有一个解决方案,但我相信可以用一种更优雅的方式来实现。我只能使用ramda,但首选香草溶液。 这是我的解决方案:
return Object.values(
data.reduce((r, e) => {
const key = `${e.uniqId}|${e.city}`;
if (!r[key]) {
r[key] = e;
if (r[key].numbers && !isEmpty(r[key].numbers)) {
r[key].numbers.push(e.number);
} else {
r[key].numbers = [];
r[key].numbers.push(e.number);
}
} else if (r[key].numbers && !isEmpty(r[key].numbers)) {
r[key].numbers.push(e.number);
} else {
r[key].numbers = [];
r[key].numbers.push(e.number);
}
return r;
}, {}),
).map((item, index) => ({ ...item, index: index }));
答案 0 :(得分:2)
您要做的工作比减速器要多
const data = [
{index: 1, number: 's1', uniqId: '123', city: 'LA'},
{index: 2, number: 's2', uniqId: '321', city: 'NY'},
{index: 3, number: 's3', uniqId: '123', city: 'LA'},
{index: 4, number: 's4', uniqId: '111', city: 'TX'},
{index: 5, number: 's5', uniqId: '321', city: 'NY'}
]
const reduced = data.reduce((acc, e) => {
const key = `${e.uniqId}|${e.city}`;
if (! (key in acc)) {
acc[key] = Object.assign({}, e);
delete acc[key]['number'];
acc[key]['numbers'] = [];
}
acc[key]['numbers'].push(e.number);
return acc;
}, {});
console.log(Object.values(reduced));
答案 1 :(得分:0)
另一种减速器功能
data.reduce((acc, curr) => {
const existingIdRow = acc.find(existingElement => existingElement.uniqId === curr.uniqId);
if(existingIdRow && existingIdRow.numbers)
existingIdRow.numbers.push(curr.number);
else {
const { uniqId, city } = curr;
acc.push({index: acc.length + 1, numbers: [curr.number], uniqId, city});
}
return acc
}, [])
答案 2 :(得分:0)
是的,您可以只使用一个reducer和一个条件循环来完成它,所以这样做比获取对象的键然后循环遍历更快。
const data = [
{index: 1, number: 's1', uniqId: '123', city: 'LA'},
{index: 2, number: 's2', uniqId: '321', city: 'NY'},
{index: 3, number: 's3', uniqId: '123', city: 'LA'},
{index: 4, number: 's4', uniqId: '111', city: 'TX'},
{index: 5, number: 's5', uniqId: '321', city: 'NY'}
]
const reducer = (accum, cv, currentIndex, source) => {
const hasValue = accum.some(entry => entry.uniqId === cv.uniqId);
// we already proccessed it.
if (hasValue) return accum;
// we create an object with the desired structure.
const {
index,
uniqId,
city,
number
} = cv;
let newObj = {
index,
uniqId,
city,
numbers: [number]
};
//now lets fill the numbers :)
source.forEach((v, index) => {
//index !== currentIndex &&
if (index !== currentIndex && v.uniqId === uniqId) {
newObj['numbers'].push(v.number);
}
})
return [...accum, newObj];
}
const result = data.reduce(reducer, []);
console.log(result)
答案 3 :(得分:0)
使用数组中的第一个对象作为映射和对象解构,可以很简单地解决这个问题:
const data = [
{index: 1, number: 's1', uniqId: '123', city: 'LA'},
{index: 2, number: 's2', uniqId: '321', city: 'NY'},
{index: 3, number: 's3', uniqId: '123', city: 'LA'},
{index: 4, number: 's4', uniqId: '111', city: 'TX'},
{index: 5, number: 's5', uniqId: '321', city: 'NY'}
]
const result = data.reduce((acc, {number,uniqId,city}) => {
if (!acc[0][uniqId]) {
acc.push(acc[0][uniqId] = {index: acc.length, numbers: [], uniqId, city});
}
acc[0][uniqId].numbers.push(number);
return acc;
}, [{}]).slice(1);
console.log(result);
答案 4 :(得分:0)
通常,您不希望有两个不同的属性来列出相似的数据,所以我要做的第一件事是创建一个map()
函数,将所有number
道具更改为numbers
并它们是单项数组。然后,我使用reduce()
函数将带有uniqId的obj分组在一起。我本来会保留它,但是由于您希望根据对象使用number
或numbers
的结果,因此我在最后写了一个简单的map()
函数,以转换回此函数格式。
const data = [
{index: 1, number: 's1', uniqId: '123', city: 'LA'},
{index: 2, number: 's2', uniqId: '321', city: 'NY'},
{index: 3, number: 's3', uniqId: '123', city: 'LA'},
{index: 4, number: 's4', uniqId: '111', city: 'TX'},
{index: 5, number: 's5', uniqId: '321', city: 'NY'}
]
let res = data.map((el) => {
el.numbers = [el.number]
delete el.number
return el
}).reduce((acc,cur) => {
let ids = acc.map(obj => obj.uniqId)
let io = ids.indexOf(cur.uniqId)
if(io > -1){
acc[io].numbers.push(cur.numbers[0])
}else{
acc.push(cur)
}
return acc
},[])
console.log(res)
res = res.map(el => {
if(el.numbers.length <= 1){
el.number = el.numbers[0]
delete el.numbers
}
return el
})
console.log(res)
答案 5 :(得分:0)
这是通过地图执行此操作的简单方法,并且逻辑上符合您的期望输出-las,与您的期望输出相比, numbers 属性位置不正确。
如果这很重要,我留给您整理;)
const data = [
{ index: 1, number: 's1', uniqId: '123', city: 'LA' },
{ index: 2, number: 's2', uniqId: '321', city: 'NY' },
{ index: 3, number: 's3', uniqId: '123', city: 'LA' },
{ index: 4, number: 's4', uniqId: '111', city: 'TX' },
{ index: 5, number: 's5', uniqId: '321', city: 'NY' }
];
const reducer = (acc, e, idx, arr) => {
const key = `${e.uniqId}|${e.city}`;
let value = acc.get(key);
if (value === undefined) {
value = Object.assign({},e);
acc.set(key, value);
value.index = acc.size;
} else {
if('number' in value) {
value.numbers = [value.number]
delete value.number;
}
value.numbers.push(e.number);
}
if (++idx === arr.length) {
return Array.from(acc.values());
}
return acc;
};
const result = data.reduce(reducer, new Map());
document.getElementById('result').innerText = JSON.stringify(result);
<code id="result"></code>