【问题标题】:How can I group specific items within an object in the same array and delete them from the core array?如何将对象中的特定项目分组到同一数组中并将它们从核心数组中删除?
【发布时间】:2021-02-22 22:41:36
【问题描述】:

我正在尝试实现一些有点复杂的事情。

我正在开发一个分组功能,我必须获取包含键 checked: true 的项目,然后我需要将它们放在名为 questionGroup 的键/数组中,并在数组的第一项中使用 checked: true然后删除分组的其他项目。

查看数据结构:

const dummyQuestions = [
  {
    id: 1,
    checked: false,
    question: {...},
    questionGroup: []
  },
  {
    id: 2,
    checked: true,
    question: {...},
    questionGroup: []
  },
  {
    id: 3,
    checked: false,
    question: {...},
    questionGroup: []
  },
  {
    id: 4,
    checked: true,
    question: {...},
    questionGroup: []
  },
  {
    id: 5,
    checked: true,
    question: {...},
    questionGroup: []
  }
];

假设您单击了某个触发分组功能的按钮,因为您注意到索引134 具有checked: true,所以这必须发生:

const dummyQuestions = [
  {
    id: 1,
    checked: false,
    question: {...},
    questionGroup: []
  },
  {
    id: 2,
    checked: true,
    question: {...},
    questionGroup: [
      {
        id: 2,
        checked: true,
        question: {...},
        questionGroup: []
      },
      {
        id: 4,
        checked: true,
        question: {...},
        questionGroup: []
      },
      {
        id: 5,
        checked: true,
        question: {...},
        questionGroup: []
      }
    ]
  },
  {
    id: 3,
    checked: false,
    question: {...},
    questionGroup: []
  }
];

分组后的数据应该是这样的。

你明白了吗?

我创建了一个可重现的演示 => https://codesandbox.io/s/ts-react-grouping-odxs1?file=/src/App.tsx

编辑

这是相关代码:

const handleGroupQuestions = (): void => {
    const questionAddedCopy: VariableConfig[] = [...questionAdded];

    // Only the questions with checked === true will be grouped.
    const filteredCopy: VariableConfig[] = questionAddedCopy.filter(
      (q: VariableConfig) => q.checked === true
    );

    const grouped: VariableConfig[] = [
      ...questionAdded.filter((q: VariableConfig) => filteredCopy.includes(q))
    ];

    for (let i = 0; i < grouped.length; i++) {
      // Here I compare the ids and I put them together into the key questionGroup
      if (filteredCopy[i].id === grouped[i].id) {
        // I had to set any instead of VariableConfig type because otherwise TS throws an error
        addQuestion((q: any) => {
          const questionsCopy = [...q];

          const mergedQuestions: VariableConfig[] = [
            ...questionsCopy,
            { ...grouped[i], questionGroup: grouped }
          ];

          // With this `unique` function what I am trying to achieve (which I am not) is
          // to have a unique ID per every question/item in the array.
          // I need to add the questions to questionGroup to the highest item containing check = true
          // I need to delete from the main array, the items going inside questionGroup.
          const unique = [
            ...mergedQuestions.filter((c) => c.id !== questionsCopy[i].id)
          ];

          return unique;
        });
        break;
      }
    }
  };

并深入解释并回答您的问题。

我们看到数组中带有checked: true 的第一个项目是ID 为2 的项目,所以这将是我必须用checked: true 存储其他项目的地方,因为这是最高的项目在数组中,然后我需要从数组中删除分组到questionGroup 中的项目。

在这种情况下 id 2 是重复的,这是一个要求,因为一个 id 是给父母的,而另一个在 questionGroup 中是它自己的孩子,明白吗?就像它将自己存储到 questionGroup 中一样。

这只是一个分组功能,我在其中节省了一些步骤。想象一下每个项目都包含一个复选框,所以你要分组的项目,你必须先检查它们,然后点击GROUP THEM按钮,选中的项目消失然后聚集到最高的选中索引,保持它的id并存储自己。

看看我发布的数组。在那里你可以看到我需要的确切输出是什么。

【问题讨论】:

  • 到目前为止你尝试过什么?如果您发布对该算法的尝试,它会更容易为您提供帮助。
  • codesandbox 演示链接中有一个算法尝试......尽管任何相关代码也应该在问题的文本中,如How to Ask 的“帮助其他人重现问题”部分所述。不过,我仍然不明白想要的结果...我想我们想从数组中删除 checked:true 项目并将它们附加到 other 项目之一的 questionGroup 属性中数组,但我不知道是哪一个,或者它只是一个,还是什么。
  • 我有点害怕在这里询问更多信息,因为我认为在我之前询问过更多信息后,这个问题已被删除并多次重新询问。我保证我只是想帮忙。
  • 我无法理解这个输出分组与输入和checked 集合的1334 有什么关系......即使我做了可能但不清楚的猜测是原始列表具有连续的ids 和12345。为什么123 在根?为什么245 嵌套在2 中?你真的想要2 嵌套在它里面吗?请edit 在此处包含您尝试的相关代码。 (不需要整个应用程序,只需执行此数据转换的功能即可。)
  • 一个基本的想法是过滤你的数组,只在项目为 check:false 时返回 true。如果 check:true,则将项目推入其他数组中。最后一件事是在正确位置迭代时插入第一个具有 check:true 的项目(并将“其他数组”中的项目作为子项附加)。我没有回答,因为不清楚为什么 id 2 在预期结果中重复

标签: javascript reactjs typescript algorithm ecmascript-6


【解决方案1】:

这是一种技术:

// helper function
const addChecked = (q, qs) =>
  ({...q, questionGroup: qs .filter (p => p .checked)})

// main function
const nestChecked = (qs, found = false) =>
  qs .flatMap (q => q .checked ? found ? [] : (found = true, [addChecked (q, qs)]) : [q])

// sample data
const dummyQuestions = [{id: 1, checked: false, question: 'foo', questionGroup: []}, {id: 2, checked: true, question: 'bar', questionGroup: []}, {id: 3, checked: false, question: 'baz', questionGroup: []}, {id: 4, checked: true, question: 'qux', questionGroup: []}, {id: 5, checked: true, question: 'corge', questionGroup: []}]

// demo
console .log  (JSON .stringify (nestChecked (dummyQuestions), null, 4))
.as-console-wrapper {max-height: 100% !important; top: 0}

我们有一个简单的辅助函数,可以将输入的所有检查元素分组到特定问题(的副本)中。

我们的 main 函数使用 .flatMap 迭代问题,这允许我们在一次遍历中进行过滤和映射。我们维护一个标志,found,它告诉我们是否已经处理了检查的元素。对于每个问题,如果未选中,我们只需将其包含在数组中,将其作为[q]flatMap 回调中返回。如果选中,我们评估found 标志。如果设置为true,那么我们返回并清空数组。如果不是,我们返回调用上面的辅助函数的结果,再次包装在一个数组中。 (这个问题并不特别需要这些数组包装器;但我喜欢在flatMap 回调中返回一致的类型。)

我们可以轻松地内联该辅助函数,因为它只被调用一次。事实上,我最初是这样写的。但我觉得分开更干净。

我不清楚是否有一些迭代过程会进一步嵌套这些。如果是这样,您可能需要在处理已填充的questionGroup 字段的辅助函数中做一些更复杂的事情。但这可能是针对不同的问题。

最后,我们可能还想避免使用该默认参数。有时有good reasons 想要这样做。我将此更改作为练习留给读者。 :-)

【讨论】:

  • 我不知道 OP 是否需要修改现有数据或制作新数据,以及是否需要以某种方式维护这些数组中的任何一个的身份。但这对我来说似乎是一个很好的解决方案。
  • @jcalz:好吧,如果 OP 想要改变原始数据,我不会有任何帮助。我不是野蛮人。 ;-)
  • 我不想改变数据。一切都好,斯科特。它正是我需要的。谢谢,伙计们。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-06-13
  • 1970-01-01
  • 2019-12-31
  • 2022-06-12
  • 2017-02-16
  • 2016-08-03
相关资源
最近更新 更多