如何将对象分组到数组中并根据对象属性对其进行排序 [英] How to group objects in an array and sort them depending on an object property

查看:33
本文介绍了如何将对象分组到数组中并根据对象属性对其进行排序的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

 groupSelectedQuestions(selectedQuestions){
     var questions = [
         { q: 'why?', group: 'no-group', date: '1' }, 
         { q: 'what?', group: 'group 1', date: '1' }, 
         { q: 'when?', group: 'group 2', date: '2' }, 
         { q: 'where?', group: 'group 1', date: '2' }, 
         { q: 'which', group: 'group 2', date: '3' }
     ],
     result = questions.reduce(function (r, a) {
         r[a.group] = r[a.group] || [];
         r[a.group].push(a);
         return r;
     }, {});
     /**
     more code here.
     Here I would put if statements that check for all condtions
     I have stated in the question below
     */
 }

我正在尝试创建一个功能,以便用户调用并按特定的组对问题进行分组.在上方,您可以看到我提供的部分代码.

I am trying to make a function that users call and groups questions in certain groups. Above you can see part of the code I have come up with.

我对如何对问题进行分组有很多条件.

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

  1. 每个小组的问题不得少于两个.
  2. 'no-group'表示该问题不在任何组中.因此,'no-group'可以只是一个问题,也可以是所有问题.
  3. 应在该组问题中最早分配组.例如,'group 1'最早的(按日期而言)问题应早于' group 2'的最早的问题,并且在重新组合问题时也应重新调整此问题.还是从群组中删除了一个问题.
  4. 已分组的问题可以重新分组.这样做时,如果一个问题只留在一个小组中,则应将其标记为'no-group'.
  5. 在采用'group 1'的情况下分配组时,分配'group 2',当采用'group 2'的情况下,分配>第3组" 等.
  1. No group can have less than two number of questions.
  2. 'no-group' means the question is not in any group. So 'no-group' can be just one question or all of them.
  3. 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.
  4. Grouped questions can be regrouped. And when doing so if any question is left in a group alone it should marked as 'no-group'.
  5. When assigning groups when 'group 1' is taken assign 'group 2', when 'group 2' is taken assign 'group 3' and so on.

我将使用if语句的方式.但是由于问题数组最多可以包含二十个问题,并且组可以从'group 1''group 2' ...到'group20',则if语句的数量将变多.

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.

我做了 stackblitz 来更好地沟通我想要达到的目标.有没有一种方法可以使用递归来实现我想要实现的目标,并避免使用许多if语句?

I made a stackblitz to communicate better what I am trying to achieve. Is there a way I can use recursion to achieve what I want to achieve and avoid many if statements?

如果有不清楚的地方请问我将很高兴将其弄清楚.

If there is something that is not clear kindly ask I will be glad to make it clear.

stackblitz中的代码如下(它是Angular stackblitz):

The code in the stackblitz is as follows (it is an Angular stackblitz):

控制器

  questions = [
    { _id:1, q: 'why?', group: 'no-group', date: '1', selected:false }, 
    { _id:2, q: 'what?', group: 'group 1', date: '1', selected:false }, 
    { _id:3, q: 'when?', group: 'group 2', date: '2', selected:false }, 
    { _id:4, q: 'where?', group: 'group 1', date: '2', selected:false }, 
    { _id:5, q: 'which?', group: 'group 2', date: '3', selected:false }
  ];

  selectOrUnselectQuestion(question){
    let newQuestions = this.questions.map(newQuestion => {
      if(newQuestion._id === question._id){
        if(!newQuestion.selected){
            newQuestion.selected = true;
          } else {
            newQuestion.selected = false;
          }
        return newQuestion;
        } else {
          return newQuestion;
        }
      })
      this.questions = newQuestions; 
  }

  groupSelectedQuestions(){
    let selectedQuestions = this.questions.filter(q => q.selected);
    let selectedQuestionIds = selectedQuestions.map(selectedQuestion=>{ return selectedQuestion._id; })
    let newQuestions = this.questions.map(question => {
      if(selectedQuestions.length==1 && selectedQuestionIds.includes(question._id)){
        question.group = 'no-group';
        question.selected = false;
        return question
      } else 
      if(selectedQuestions.length>1 && selectedQuestionIds.includes(question._id)){
        question.group = 'group 1';
        question.selected = false;
        return question
      } else {
        return question;
      }
    })
    this.questions = newQuestions;

    // deselect selected questions

  }

视图:

<div style="text-align:center">Questions</div>

<div style="text-align:center; padding:10px;">

    <div *ngFor="let question of questions" (click)="selectOrUnselectQuestion(question)"
        [ngClass]="{'selected': question.selected}" class="question">
        <span style="padding-right:10px">{{question.q}}</span>
        <span>{{question.group}}</span>
    </div>

    <button (click)="groupSelectedQuestions()" style="margin:10px 0" type="button">
    group selected questions
  </button>

</div>

推荐答案

恐怕评论中的讨论并不能帮助我理解.

I'm afraid that the discussion in the comments did not do much to help me understand.

这是仍然会猜测您的某些要求的尝试:

Here is an attempt that still guesses at some of your requirements:

// utility functions
const groupBy = (prop) => (xs) => 
  xs .reduce (
    (a, {[prop]: p, ...rest}) => ({...a, [p]: [...(a[p] || []), rest]}),
    {}
  )

const partition = (pred) => (xs) =>
  xs .reduce (([yes, no], x) => pred (x) ? [[...yes, x], no] : [yes, [...no, x]], [[], []])

// main function
const makeGroups = questions => {
  const {'no-group': groupless, ...rest} = groupBy ('group') (questions)
  const [largeEnough, tooSmall] = partition ((v) => v.length > 1) (Object .values (rest))
  const noGroup = [...groupless, ...tooSmall.flat()].sort((a, b) => a.date - b.date)
  return {
    ...Object .fromEntries (
      largeEnough
        .map (group => group.sort ((a, b) => a .date - b .date))
        .sort ((group1, group2) => group1 [0] .date - group2 [0] .date)
        .map ((group, i) => [`group ${i + 1}`, group])
    ),
    'no-group': noGroup
  }
}

// sample data
const questions = [
  {_id: 1, q: 'why?', group: 'no-group', date: '8', selected: false }, 
  {_id: 2, q: 'what?', group: 'A', date: '6', selected: false }, 
  {_id: 3, q: 'when?', group: 'C', date: '7', selected: false }, 
  {_id: 4, q: 'where?', group: 'A', date: '5', selected: false }, 
  {_id: 5, q: 'which?', group: 'B', date: '3', selected: false },
  {_id: 6, q: 'who?', date: '0', selected: false }, // no group supplied so will end up in no-group
  {_id: 7, q: 'why not?', group: 'B', date: '9', selected: false }, 
  {_id: 8, q: 'who, me?', group: 'A', date: '4', selected: false }, 
  {_id: 9, q: 'where is waldo?', group: 'A', date: '1', selected: false }, 
  {_id: 10, q: 'which way is up?', group: 'B', date: '2', selected: false },
  {_id: 11, q: 'when is lunch?', group: 'D', date: '10', selected: false }, 
];
// demo
console .log (makeGroups (questions))

.as-console-wrapper {max-height: 100% !important; top: 0}

输出将如下所示:

{
  'group 1': [
    {_id: 9, q: "where is waldo?", date: "1", selected: false},
    {_id: 8, q: "who, me?", date: "4", selected: false},
    {_id: 4, q: "where?", date: "5", selected: false},
    {_id: 2, q: "what?", date: "6", selected: false}
  ],
  'group 2': [
    {_id: 10, q: "which way is up?", date: "2", selected: false},
    {_id: 5, q: "which?", date: "3", selected: false},
    {_id: 7, q: "why not?", date: "9", selected: false}
  ],
  'no-group': [
    {_id: 6, q: "who?", date: "0", selected: false},
    {_id: 3, q: "when?", date: "7", selected: false},
    {_id: 1, q: "why?", date: "8", selected: false},
    {_id: 11, q: "when is lunch?", date: "10",selected: false}
  ]
}

组在内部按日期排序,组之间按列表中的第一个日期排序.没有至少两个条目的任何组将被折叠为 no-group ,并按顺序分配组号.

The groups are internally sorted by date, and the groups are sorted between them by the first date in their list. Any group without at least two entries is folded into no-group and the group numbers are assigned sequentially.

最大的问题是,这是否符合您的需求.如果没有,您可以像我在这里一样显示示例输入和预期输出吗?

The big question is whether this fits your needs. If not, can you show a sample input and expected output as I have done here?

尽管我是辅助函数的忠实拥护者,我偶尔会使用该<​​code> partition 和该 groupBy 的泛化版本,但我想指出因为每个仅使用一次,所以我们可以非常简单地内联它们:

Although I'm a big fan of helper functions and I use that partition occasionally and a slightly generalized version of that groupBy quite frequently, I'd like to point out that as each is only used once, we could inline them quite simply:

const makeGroups = questions => {
  const {'no-group': groupless, ...rest} = questions .reduce (
    (a, {group = 'no-group', ...rest}) => ({...a, [group]: [...(a[group] || []), rest]}),
    {}
  )
  const [largeEnough, tooSmall] = Object .values (rest) .reduce (
      ([yes, no], x) => x.length > 1 ? [[...yes, x], no] : [yes, [...no, x]], [[], []]
  )
  const noGroup = [...groupless, ...tooSmall.flat()].sort((a, b) => a.date - b.date)
  return {
    ...Object .fromEntries (
      largeEnough
        .map (group => group.sort ((a, b) => a .date - b .date))
        .sort ((group1, group2) => group1 [0] .date - group2 [0] .date)
        .map ((group, i) => [`group ${i + 1}`, group])
    ),
    'no-group': noGroup
  }
}

这篇关于如何将对象分组到数组中并根据对象属性对其进行排序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆