How to sort an array of objects using two properties but conditionally group in the sort order depending on a condition?

て烟熏妆下的殇ゞ 提交于 2021-02-08 15:42:24

问题


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:


  • sort the array by date
  • reduce the array with a Map as accumulator.
  • If it's a no-group item, add a new entry to the Map with a unique _id as key.
  • If it is an item with a valid group, then use the group as the key and an array of items which have the same group.
  • Every no-group will be added as a key in Map. The rest of the items will be added based on the first entry for that group.
  • 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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!