对于一组用户项,如何合并用户名和附加唯一 属性 名称相等的连续用户项的条目?
How does one, for an array of user items, merge the entries of consecutive user items where user name and an additional sole property name are equal?
假设一个数组具有如下不一致的属性:
[
{user: 'user1', comment: 'This is a comment',},
{user: 'user1', role: 'member'},
{user: 'user1', role: 'writer'},
{user: 'user2', role: 'admin'},
{user: 'user1', comment: 'This is another comment'},
]
如何转动它以便将对象分组 仅
如果数组中的下一个元素具有相同的 属性 并且属于同一用户 :
[
{user: 'user1', comment: 'This is a comment'},
{user: 'user1', role: [{'member', 'writer'}]},
{user: 'user2', role: 'admin'},
{user: 'user1', comment: 'This is another comment'},
]
你可以使用 reduce 做类似的事情
const datas = [
{ user: 'user1', comment: 'This is a comment' },
{ user: 'user1', role: 'member' },
{ user: 'user1', role: 'writer' },
{ user: 'user1', role: 'observer' },
{ user: 'user2', comment: 'This is a comment' },
{ user: 'user2', role: 'writer' },
{ user: 'user2', role: 'admin' },
{ user: 'user1', role: 'admin' },
{ user: 'user1', role: 'observer' },
{ user: 'user3', comment: 'This is another comment' },
{ user: 'user3', comment: 'And this is yet another comment' },
{ user: 'user2', comment: 'Yet another comment' },
];
const datas2 = datas.reduce((s, d, x) => {
if (x > 0) {
const dk = Object.keys(d)
if (dk.join(',') === Object.keys(s[s.length - 1]).join(',') && d.user === s[s.length - 1].user) {
for (const k in dk) {
if (dk[k] !== 'user' && d.hasOwnProperty(dk[k]) && s[s.length - 1].hasOwnProperty(dk[k])) {
if (typeof s[s.length - 1][dk[k]] !== 'object')
s[s.length - 1][dk[k]] = [s[s.length - 1][dk[k]]]
s[s.length - 1][dk[k]].push(d[dk[k]])
}
}
return s
}
}
return s.concat(d)
}, [])
console.log(datas2);
.as-console-wrapper { min-height: 100%!important; top: 0; }
你可以试试这样的递归函数
let data = [
{ user: 'user1', comment: 'This is a comment' },
{ user: 'user1', role: 'member' },
{ user: 'user1', role: 'writer' },
{ user: 'user1', role: 'observer' },
{ user: 'user2', comment: 'This is a comment' },
{ user: 'user2', role: 'writer' },
{ user: 'user2', role: 'admin' },
{ user: 'user1', role: 'admin' },
{ user: 'user1', role: 'observer' },
{ user: 'user3', comment: 'This is another comment' },
{ user: 'user3', comment: 'And this is yet another comment' },
{ user: 'user2', comment: 'Yet another comment' },
];
let combined = []
const combineRole = (curr, next, data) => {
if (curr.user == next?.user && curr.role && next.role) {
curr.role = [curr.role, next.role].flat().filter(Boolean)
return combineRole(curr, data.shift(), data)
} else {
return [curr, next]
}
}
while (data.length) {
// console.log(data)
let [curr, next] = (combineRole(data.shift(), data.shift(), data))
if (next)
data.unshift(next)
combined.push(curr)
}
console.log(combined)
.as-console-wrapper { min-height: 100%!important; top: 0; }
此解决方案也是作为 reduce
任务实施的。
迭代任务采用后视方法,将当前用户项目与前一个用户项目进行比较。如果满足两个匹配条件(相同的用户名和相同的 属性 名称),该过程会尝试查找已存在的 merger
对象,该对象将通过 collector
对象引用。如果之前的合并没有发生,则会从之前的用户项目创建一个新的 merger
对象并将其分配给 collector
。在任何情况下,合并都将由当前处理的用户项目聚合。
function mergeConsecutiveSameSoleUserEntry(collector, userItem, idx, arr) {
let { merger, result } = collector;
let isProceedUnmerged = true;
if (idx >= 1) {
const { user: userName, ...soleEntry } = userItem;
const { user: prevUserName, ...prevSoleEntry } = arr[idx - 1] ?? {};
if (userName === prevUserName) {
const [soleKey, soleValue] = Object.entries(soleEntry).at(0);
const [prevSoleKey, prevSoleValue] = Object.entries(prevSoleEntry).at(0);
if (soleKey === prevSoleKey) {
if (!merger) {
merger = collector.merger = {
user: userName,
[soleKey]: [prevSoleValue],
};
result[result.length - 1] = merger;
}
merger[soleKey].push(soleValue);
isProceedUnmerged = false;
}
}
}
if (isProceedUnmerged) {
Reflect.deleteProperty(collector, 'merger');
result.push(userItem);
}
return collector;
}
console.log([
{ user: 'user1', comment: 'This is a comment' },
{ user: 'user1', role: 'member' },
{ user: 'user1', role: 'writer' },
{ user: 'user1', role: 'observer' },
{ user: 'user2', comment: 'This is a comment' },
{ user: 'user2', role: 'writer' },
{ user: 'user2', role: 'admin' },
{ user: 'user1', role: 'admin' },
{ user: 'user1', role: 'observer' },
{ user: 'user3', comment: 'This is another comment' },
{ user: 'user3', comment: 'And this is yet another comment' },
{ user: 'user2', comment: 'Yet another comment' },
].reduce(mergeConsecutiveSameSoleUserEntry, { result: [] }).result);
.as-console-wrapper { min-height: 100%!important; top: 0; }
假设一个数组具有如下不一致的属性:
[
{user: 'user1', comment: 'This is a comment',},
{user: 'user1', role: 'member'},
{user: 'user1', role: 'writer'},
{user: 'user2', role: 'admin'},
{user: 'user1', comment: 'This is another comment'},
]
如何转动它以便将对象分组 仅 如果数组中的下一个元素具有相同的 属性 并且属于同一用户 :
[
{user: 'user1', comment: 'This is a comment'},
{user: 'user1', role: [{'member', 'writer'}]},
{user: 'user2', role: 'admin'},
{user: 'user1', comment: 'This is another comment'},
]
你可以使用 reduce 做类似的事情
const datas = [
{ user: 'user1', comment: 'This is a comment' },
{ user: 'user1', role: 'member' },
{ user: 'user1', role: 'writer' },
{ user: 'user1', role: 'observer' },
{ user: 'user2', comment: 'This is a comment' },
{ user: 'user2', role: 'writer' },
{ user: 'user2', role: 'admin' },
{ user: 'user1', role: 'admin' },
{ user: 'user1', role: 'observer' },
{ user: 'user3', comment: 'This is another comment' },
{ user: 'user3', comment: 'And this is yet another comment' },
{ user: 'user2', comment: 'Yet another comment' },
];
const datas2 = datas.reduce((s, d, x) => {
if (x > 0) {
const dk = Object.keys(d)
if (dk.join(',') === Object.keys(s[s.length - 1]).join(',') && d.user === s[s.length - 1].user) {
for (const k in dk) {
if (dk[k] !== 'user' && d.hasOwnProperty(dk[k]) && s[s.length - 1].hasOwnProperty(dk[k])) {
if (typeof s[s.length - 1][dk[k]] !== 'object')
s[s.length - 1][dk[k]] = [s[s.length - 1][dk[k]]]
s[s.length - 1][dk[k]].push(d[dk[k]])
}
}
return s
}
}
return s.concat(d)
}, [])
console.log(datas2);
.as-console-wrapper { min-height: 100%!important; top: 0; }
你可以试试这样的递归函数
let data = [
{ user: 'user1', comment: 'This is a comment' },
{ user: 'user1', role: 'member' },
{ user: 'user1', role: 'writer' },
{ user: 'user1', role: 'observer' },
{ user: 'user2', comment: 'This is a comment' },
{ user: 'user2', role: 'writer' },
{ user: 'user2', role: 'admin' },
{ user: 'user1', role: 'admin' },
{ user: 'user1', role: 'observer' },
{ user: 'user3', comment: 'This is another comment' },
{ user: 'user3', comment: 'And this is yet another comment' },
{ user: 'user2', comment: 'Yet another comment' },
];
let combined = []
const combineRole = (curr, next, data) => {
if (curr.user == next?.user && curr.role && next.role) {
curr.role = [curr.role, next.role].flat().filter(Boolean)
return combineRole(curr, data.shift(), data)
} else {
return [curr, next]
}
}
while (data.length) {
// console.log(data)
let [curr, next] = (combineRole(data.shift(), data.shift(), data))
if (next)
data.unshift(next)
combined.push(curr)
}
console.log(combined)
.as-console-wrapper { min-height: 100%!important; top: 0; }
此解决方案也是作为 reduce
任务实施的。
迭代任务采用后视方法,将当前用户项目与前一个用户项目进行比较。如果满足两个匹配条件(相同的用户名和相同的 属性 名称),该过程会尝试查找已存在的 merger
对象,该对象将通过 collector
对象引用。如果之前的合并没有发生,则会从之前的用户项目创建一个新的 merger
对象并将其分配给 collector
。在任何情况下,合并都将由当前处理的用户项目聚合。
function mergeConsecutiveSameSoleUserEntry(collector, userItem, idx, arr) {
let { merger, result } = collector;
let isProceedUnmerged = true;
if (idx >= 1) {
const { user: userName, ...soleEntry } = userItem;
const { user: prevUserName, ...prevSoleEntry } = arr[idx - 1] ?? {};
if (userName === prevUserName) {
const [soleKey, soleValue] = Object.entries(soleEntry).at(0);
const [prevSoleKey, prevSoleValue] = Object.entries(prevSoleEntry).at(0);
if (soleKey === prevSoleKey) {
if (!merger) {
merger = collector.merger = {
user: userName,
[soleKey]: [prevSoleValue],
};
result[result.length - 1] = merger;
}
merger[soleKey].push(soleValue);
isProceedUnmerged = false;
}
}
}
if (isProceedUnmerged) {
Reflect.deleteProperty(collector, 'merger');
result.push(userItem);
}
return collector;
}
console.log([
{ user: 'user1', comment: 'This is a comment' },
{ user: 'user1', role: 'member' },
{ user: 'user1', role: 'writer' },
{ user: 'user1', role: 'observer' },
{ user: 'user2', comment: 'This is a comment' },
{ user: 'user2', role: 'writer' },
{ user: 'user2', role: 'admin' },
{ user: 'user1', role: 'admin' },
{ user: 'user1', role: 'observer' },
{ user: 'user3', comment: 'This is another comment' },
{ user: 'user3', comment: 'And this is yet another comment' },
{ user: 'user2', comment: 'Yet another comment' },
].reduce(mergeConsecutiveSameSoleUserEntry, { result: [] }).result);
.as-console-wrapper { min-height: 100%!important; top: 0; }