问题
This question is a continuation to this question.
Lets say I have an array like below:
const questions = [
{_id: 1, q: 'why?', group: 'no-group', date: '8', selected: false },
{_id: 2, q: 'what?', group: 'group 1', date: '6', selected: false },
{_id: 3, q: 'when?', group: 'no-group', date: '7', selected: false },
{_id: 4, q: 'where?', group: 'group 1', date: '5', selected: false },
{_id: 5, q: 'which?', group: 'group 2', date: '3', selected: false },
{_id: 6, q: 'who?', group: 'no-group', date: '0', selected: false },
{_id: 7, q: 'why not?', group: 'group 2', date: '9', selected: false },
{_id: 8, q: 'who, me?', group: 'group 1', date: '4', selected: false },
{_id: 9, q: 'where is waldo?', group: 'group 1', date: '1', selected: false },
{_id: 10, q: 'which way is up?', group: 'no-group', date: '2', selected: false },
{_id: 11, q: 'when is lunch?', group: 'group-2', date: '10', selected: false },
];
How can I write code to sort it so that the objects are sorted by date and by group. But if: lets say group 1 appears as the second object, then the following objects should be group 1 sorted by date until all group one objects are listed and the same for all other objects except objects that have 'no-group' as the group property value.
So for the array above I should get an output like below:
[
{_id: 6, q: 'who?', group: 'no-group', date: '0', selected: false },
{_id: 9, q: 'where is waldo?', group: 'group 1', date: '1', selected: false },
{_id: 8, q: 'who, me?', group: 'group 1', date: '4', selected: false },
{_id: 4, q: 'where?', group: 'group 1', date: '5', selected: false },
{_id: 2, q: 'what?', group: 'group 1', date: '6', selected: false },
{_id: 10, q: 'which way is up?', group: 'no-group', date: '2', selected: false },
{_id: 5, q: 'which?', group: 'group 2', date: '3', selected: false },
{_id: 7, q: 'why not?', group: 'group 2', date: '9', selected: false },
{_id: 11, q: 'when is lunch?', group: 'group 2', date: '10', selected: false },
{_id: 3, q: 'when?', group: 'no-group', date: '7', selected: false },
{_id: 1, q: 'why?', group: 'no-group', date: '8', selected: false },
];
// the spacing is just for easier readability.
回答1:
You could sort by date, group by unsing an object for same groups and get a flat array.
const
questions = [{ _id: 1, q: 'why?', group: 'no-group', date: '8', selected: false }, { _id: 2, q: 'what?', group: 'group 1', date: '6', selected: false }, { _id: 3, q: 'when?', group: 'no-group', date: '7', selected: false }, { _id: 4, q: 'where?', group: 'group 1', date: '5', selected: false }, { _id: 5, q: 'which?', group: 'group 2', date: '3', selected: false }, { _id: 6, q: 'who?', group: 'no-group', date: '0', selected: false }, { _id: 7, q: 'why not?', group: 'group 2', date: '9', selected: false }, { _id: 8, q: 'who, me?', group: 'group 1', date: '4', selected: false }, { _id: 9, q: 'where is waldo?', group: 'group 1', date: '1', selected: false }, { _id: 10, q: 'which way is up?', group: 'no-group', date: '2', selected: false }, { _id: 11, q: 'when is lunch?', group: 'group 2', date: '10', selected: false }],
result = questions
.sort((a, b) => a.date - b.date)
.map((groups => o => {
if (o.group === 'no-group') return o;
if (groups[o.group]) {
groups[o.group].push(o);
return [];
}
return groups[o.group] = [o];
})({}))
.flat();
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
回答2:
sortthe array bydatereducethe array with aMapas accumulator.- If it's a
no-groupitem, add a new entry to theMapwith a unique_idas key. - If it is an item with a valid
group, then use thegroupas the key and an array of items which have the samegroup. - Every
no-groupwill be added as a key in Map. The rest of the items will be added based on the first entry for thatgroup. - Get the values of the map and faltten it
const questions = [{ _id: 1, q: 'why?', group: 'no-group', date: '8', selected: false }, { _id: 2, q: 'what?', group: 'group 1', date: '6', selected: false }, { _id: 3, q: 'when?', group: 'no-group', date: '7', selected: false }, { _id: 4, q: 'where?', group: 'group 1', date: '5', selected: false }, { _id: 5, q: 'which?', group: 'group 2', date: '3', selected: false }, { _id: 6, q: 'who?', group: 'no-group', date: '0', selected: false }, { _id: 7, q: 'why not?', group: 'group 2', date: '9', selected: false }, { _id: 8, q: 'who, me?', group: 'group 1', date: '4', selected: false }, { _id: 9, q: 'where is waldo?', group: 'group 1', date: '1', selected: false }, { _id: 10, q: 'which way is up?', group: 'no-group', date: '2', selected: false }, { _id: 11, q: 'when is lunch?', group: 'group 2', date: '10', selected: false }]
const group = questions.sort((a, b) => a.date - b.date)
.reduce((map, o) =>
o.group === 'no-group'
? map.set(o._id, o)
: map.set(o.group, [...map.get(o.group) || [], o] )
, new Map)
const output = Array.from(group.values()).flat()
console.log( output )
The reason for using Map instead of an object as an accumulator is that the order of keys in an object is not the order in which they were inserted. The numeric keys will be enumerated first and it will not work as intended.
回答3:
We can sort it by date first, then group the objects by group and save the groups in an object and also save the index of the groups.
Then we can finally insert the groups at the right index to get the final array:
const
groups = [{ _id: 1, q: 'why?', group: 'no-group', date: '8', selected: false }, { _id: 2, q: 'what?', group: 'group 1', date: '6', selected: false }, { _id: 3, q: 'when?', group: 'no-group', date: '7', selected: false }, { _id: 4, q: 'where?', group: 'group 1', date: '5', selected: false }, { _id: 5, q: 'which?', group: 'group 2', date: '3', selected: false }, { _id: 6, q: 'who?', group: 'no-group', date: '0', selected: false }, { _id: 7, q: 'why not?', group: 'group 2', date: '9', selected: false }, { _id: 8, q: 'who, me?', group: 'group 1', date: '4', selected: false }, { _id: 9, q: 'where is waldo?', group: 'group 1', date: '1', selected: false }, { _id: 10, q: 'which way is up?', group: 'no-group', date: '2', selected: false }, { _id: 11, q: 'when is lunch?', group: 'group 2', date: '10', selected: false }];
const sort = (groups) => {
const groupSorted = groups.sort((a, b) => a.date - b.date)
.reduce((r, o, i) => {
if (o.group !== 'no-group') {
r[o.group] = (r[o.group] || []).concat(o);
//insert the index of the group
r.index[o.group] = r.index[o.group] || i;
} else {
r.res.push(o)
}
return r;
}, {
index: {},
res: []
});
Object.entries(groupSorted.index).forEach(([group, idx]) => {
groupSorted.res.splice(idx, 0, groupSorted[group])
});
return groupSorted.res.flat();
}
console.log(sort(groups))
来源:https://stackoverflow.com/questions/65234873/how-to-sort-an-array-of-objects-using-two-properties-but-conditionally-group-in