0

This question is related to this and this questions.

I have an array like so.

const questions = [
  { _id: 1, q: 'why?', group: 'no-group', date: '8', selected: false },
  { _id: 2, q: 'what?',group: 'no-group', date: '6', selected: false },
  { _id: 3, q: 'when?',group: 'no-group', date: '7', selected: false },
  { _id: 4, q: 'where?',group: 'no-group',date: '5', selected: false },
  { _id: 5, q: 'which?',group: 'no-group',date: '3', selected: false },
  { _id: 6, q: 'who?', group: 'no-group', date: '0', selected: false },
  { _id: 7, q: 'why not?', group: 'no-group', date: '9', selected: false },
  { _id: 8, q: 'who, me?', group: 'no-group', date: '4', selected: false },
  { _id: 9, q: 'where is waldo?', group: 'no-group', 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: 'no-group', date: '10', selected: false },
];

// function takes an array of selected questions as an argument
function groupSelectedQuestions(selectedQsIds) {
  let newQuestions = questions.map(question => {
    if (selectedQsIds.length == 1 && selectedQsIds.includes(question._id)) {
      question.group = 'no-group';
      return question
    } else
    if (selectedQsIds.length > 1 && selectedQsIds.includes(question._id)) {
      question.group = 'group 1';
      return question
    } else {
      return question;
    }
  })
  return newQuestions
}

console.log(groupSelectedQuestions([1, 2, 5]))

From the code above you can group and ungroup questions.

I have a number of conditions on how I want to add the group property value to the questions.

  1. No group can have less than two number of questions. 'no-group' means the question is not in any group. So 'no-group' can be just one question or all of them.
  2. Groups should be assigned by the earliest date in the questions of that group. For example 'group 1' earliest(in terms of date) question should be earlier than the earliest question in 'group 2' and this should also be readjusted when questions are regrouped or if a question is removed from a group.
  3. Grouped questions can be regrouped. And when doing so if any question is left in a group alone it should marked as 'no-group'.
  4. When assigning groups when 'group 1' is taken assign 'group 2', when 'group 2' is taken assign 'group 3' and so on.
  5. The order of the array should remain the same as the original.

The way I would do it is use if statements. But since the array of questions can have up to twenty questions and the groups can go from 'group 1', 'group 2'... to 'group 20', the number of if statements will become many.

So every time the groupSelectedQuestions() function is called the group property in the affected questions should be updated accordingly.

For example if I questions of _id 1, 2 and 3 are selected and grouped. They should have the key value: group: "group 1". Then, if the questions of _id 4, 5 and 6 are selected and grouped they, the newly grouped 3 questions, should have the key value: group: "group 1" and the earlier grouped questions should have the key value: group: "group 2". Because the new group 1's earliest date is earlier then the new group-2's earliest date.

Basically I am trying to achieve what was done by this answer without bundling the arrays in objects and without changing the order of the array.

4
  • What is your procedure for ungrouping? Does that happen one by one? Commented Dec 10, 2020 at 20:09
  • grouping means assigning no-group. So if you pass 1 Id to the groupSelectedQuestions() then it will be marked as no-group thus ungrouped. Commented Dec 10, 2020 at 20:17
  • OK. Your date property values are strings. Should they be ordered in string lexical order? Or are they really numbers and to be ordered numerically? Commented Dec 10, 2020 at 20:17
  • As numbers. They are just a placeholder for simplification. In the production code they are actual dates. Commented Dec 10, 2020 at 20:19

1 Answer 1

1

I would suggest that you would first just assign a new group name to the selected questions, and then go through all the questions to see what needs to be updated:

  • The minimal value for date should be determined for each group, and the size of the group
  • Following the order of increasing minimal date, these groups should be reassigned a name with increasing suffix, or "no-group" if their size is 1.

So you would still sort, but just temporary, without affecting questions itself.

Here is how that could be coded:

function groupSelectedQuestions(selectedQsIds) {
    // First naively assign matches to a group "new":
    for (let q of questions) {
        if (selectedQsIds.includes(q._id)) q.group = "new";
    }
    // Collect questions by group
    let map = new Map;
    for (let q of questions) {
        let group = map.get(q.group);
        if (!group) map.set(q.group, group = { date: q.date, count: 0, questions: [] });
        group.questions.push(q);
        group.count++;
    }
    // Get selected questions
    let newGroup = map.get("new").questions;
    // Ignore the no-group group:
    map.delete("no-group");
    // Re-assign group names from scratch
    let grpNo = 1;
    for (group of Array.from(map.values()).sort((a, b) => a.date - b.date)) {
        let groupName = group.count > 1 ? "group-" + grpNo++ : "no-group";
        for (let q of group.questions) q.group = groupName;
    }
    return newGroup;
}

function groupOf(id) {
    return questions.find(q => q._id === id).group;
}

// demo
const questions = [
  { _id: 1, q: 'why?', group: 'no-group', date: '8', selected: false },
  { _id: 2, q: 'what?',group: 'no-group', date: '6', selected: false },
  { _id: 3, q: 'when?',group: 'no-group', date: '7', selected: false },
  { _id: 4, q: 'where?',group: 'no-group',date: '5', selected: false },
  { _id: 5, q: 'which?',group: 'no-group',date: '3', selected: false },
  { _id: 6, q: 'who?', group: 'no-group', date: '0', selected: false },
  { _id: 7, q: 'why not?', group: 'no-group', date: '9', selected: false },
  { _id: 8, q: 'who, me?', group: 'no-group', date: '4', selected: false },
  { _id: 9, q: 'where is waldo?', group: 'no-group', 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: 'no-group', date: '10', selected: false },
];

// Some actions...
groupSelectedQuestions([1, 2, 3]);
console.log(groupOf(1)); // group-1
groupSelectedQuestions([4, 5, 6]); // becomes group-1
console.log(groupOf(1), groupOf(4)); // group-2, group-1
groupSelectedQuestions([6, 9]); // becomes group-1
console.log(groupOf(1), groupOf(4), groupOf(6)); // group-3, group-2, group-1
groupSelectedQuestions([2, 3, 4]); // orphanes the entries with id 1 and 5
console.log(groupOf(1), groupOf(4), groupOf(5), groupOf(6)); // no-group, group-2, no-group, group-1

NB: I assumed that the order of date is determined by a subtraction (a.date - b.date). Adapt this when the actual data type of date needs a different comparator.

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

2 Comments

This is amazing. I was stuck on this issue this has saved me. Thank you. I just do not understand why one would downvote the question without any further explanation.
Indeed there is no reason for a downvote, I gave it my vote.

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.