5

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.

3 Answers 3

4

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; }

Sign up to request clarification or add additional context in comments.

Comments

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.

Comments

1

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))

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.