【问题标题】:Creating new data object set from multiple nested arrays从多个嵌套数组创建新数据对象集
【发布时间】:2019-10-13 12:03:05
【问题描述】:

我有一个复杂的数据结构,其中包含多个嵌套数组。

下面是当前结构

var contentData = {
  data: {
    content: [
      {
        type: "column",
        sections: [
          {
            sub: [
              {
                type: "heading-1",
                text: "Heading Text"
              }
            ]
          }
        ]
      },
      {
        type: "acc-item",
        sections: [
          {
            sub: [
              {
                type: "heading-1",
                text: "Heading Text"
              },
              {
                type: "ordered-item",
                text: "Item 1"
              },
              {
                type: "unordered-item",
                text: "Item 2"
              }
            ]
          }
        ]
      },
      {
        type: "acc-item",
        sections: [
          {
            sub: [
              {
                type: "heading-1",
                text: "Heading Text 2"
              }
            ]
          }
        ]
      }
    ]
  }
}

所以我想要的是,

  1. 我想将所有ordered-item & unordered-item 组合成一个新对象,例如{type: 'list', items:[all list items]}。

  2. 我需要提取 sub 中的所有项目并将其推送到新对象 embedded 并且它应该像下面那样放在根级别,

    {type:"acc-item",embedded:[{type:"heading-1",text:"Heading Text 2"}]};

所以到目前为止我做了什么,

我可以对acc-item 进行分组,但不能对ordered-item & unordered-item 进行分组。

所以我最终的预期结果应该是这样的,

[{
  "type": "column",
  "embedded": [
    {
      "type": "heading-1",
      "text": "Heading Text"
    }
  ]
},
{
  "type": "acc-group",
  "items": [
    {
      "type": "acc-item",
      "embedded": [
        {
          "type": "heading-1",
          "text": "Heading Text"
        },
        {
          "type": "list",
          "items": [
            {
              "type": "ordered-item",
              "text": "Item 1"
            },
            {
              "type": "unordered-item",
              "text": "Item 2" 
            }
          ]
        }
      ]
    },
    {
      "type": "acc-item",
      "embedded": [
        {
          "type": "heading-1",
          "text": "Heading Text 2"
        }
      ]
    }
  ]
}]

下面是我的代码,

var group,contentData={data:{content:[{type:"column",sections:[{sub:[{type:"heading-1",text:"Heading Text"}]}]},{type:"acc-item",sections:[{sub:[{type:"heading-1",text:"Heading Text"},{type:"ordered-item",text:"Item 1"},{type:"unordered-item",text:"Item 2"}]}]},{type:"acc-item",sections:[{sub:[{type:"heading-1",text:"Heading Text 2"}]}]}]}},types=[["list",["ordered-item","unordered-item"]],["accordion",["acc-item"]]];

var result = contentData.data.content.reduce((r, o) => {
  var type = (types.find(({ 1: values }) => values.indexOf(o.type) > -1)|| {})[0];
  if (!type) {
    r.push(o);
    group = undefined;
    return r;
  }
  if (!group || group.type !== type) {
    group = { type, items: [] };
    r.push(group);
  }
  group.items.push(o);
  return r;
}, []);

document.body.innerHTML = '<pre>' + JSON.stringify(result, null, '  ') + '</pre>';

【问题讨论】:

    标签: javascript arrays typescript multidimensional-array


    【解决方案1】:

    您可以存储最后一个 items 数组以及最后一个嵌入数组并使用它们直到找到列类型。

    var contentData = { data: { content: [{ type: "column", sections: [{ sub: [{ type: "heading-1", text: "Heading Text" }] }] }, { type: "acc-item", sections: [{ sub: [{ type: "heading-1", text: "Heading Text" }, { type: "ordered-item", text: "Item 1" }, { type: "unordered-item", text: "Item 2" }] }] }, { type: "acc-item", sections: [{ sub: [{ type: "heading-1", text: "Heading Text 2" }] }] }] } },
        list = ["ordered-item", "unordered-item"],
        lastItems, lastEmbedded,
        result = contentData.data.content.reduce((r, { type, sections }) => {
            if (type === 'column') {
                r.push({ type, embedded: sections.reduce((q, { sub }) => q.concat(sub), []) });
                lastItems = undefined;
                lastEmbedded = undefined;
                return r;
            }
            if (!lastItems) r.push({ type: "acc-group", items: lastItems = [] });
            lastItems.push(...sections.map(({ sub }) => ({
                type,
                embedded: sub.reduce((q, o) => {
                    if (list.includes(o.type)) {
                        if (!lastEmbedded) q.push({ type: 'list', items: lastEmbedded = [] });
                        lastEmbedded.push(o);
                    } else {
                        q.push(o);
                        lastEmbedded = undefined;
                    }
                    return q;
                }, [])
            })));
            return r;
        }, []);
    
    console.log(result);
    .as-console-wrapper { max-height: 100% !important; top: 0; }

    【讨论】:

    • 一个问题,"ordered-item", "unordered-item" 没有在列内分组
    • 你能用这个var contentData={data:{content:[{type:"column",sections:[{sub:[{type:"heading-1",text:"Heading Text"},{type:"ordered-item",text:"Item 1"},{type:"unordered-item",text:"Item 2"}]}]},{type:"acc-item",sections:[{sub:[{type:"heading-1",text:"Heading Text"},{type:"ordered-item",text:"Item 1"},{type:"unordered-item",text:"Item 2"}]}]},{type:"acc-item",sections:[{sub:[{type:"heading-1",text:"Heading Text 2"}]}]},{type:"column",sections:[{sub:[{type:"heading-1",text:"Heading Text"},{type:"ordered-item",text:"Item 1"},{type:"unordered-item",text:"Item 2"}]}]}]}};
    • 结果如何?
    • 列表没有在列内分组,所以预期结果[{type:"column",embedded:[{type:"heading-1",text:"Heading Text"},{type:"list",items:[{type:"ordered-item",text:"Item 1"},{type:"unordered-item",text:"Item 2"}]}]}];
    【解决方案2】:

    Array.prototype 和 Object.prototype 方法非常适合这种事情。

    你说得对,这是一种复杂的逻辑。

    我建议您肯定需要为此进行一些单元测试,并尝试拆分为单独的部分。

    这就是我的想法。

    1.按类型分组以创建您的组。。

    我实际上正在创建一个您在这里要求的更通用的解决方案。也就是说,我不只是对“acc-item”进行分组,而是对所有内容进行分组。

    我快速搜索了 'array group by javascript',它给了我们this answer,它建议使用 Array.reduce,所以让我们这样做。

        const groupedData = contentData.data.content.reduce((acc, cur) => {
            //Check if this indexed array already exists, if not create it. 
            const currentArray = (acc[`${cur.type}-group`] && acc[`${cur.type}-group`].items) || [];
    
            return {
              ...acc,
              [`${cur.type}-group`]: {
                  type: `${cur.type}-group`, 
                  items: [...currentArray, cur]
              }
            }
        }, {}); 
    

    2。现在对于这些项目中的每一个,我们需要查看它们的子项,并将列表项分组。

    为此,我们基本上想找到所有的 `item -> section -> sub -> 类型并将它们过滤成两个数组。关于如何使用过滤器创建两个数组的快速谷歌给了我this answer.

    不过,首先,我们需要展平那些部分-> subs 的东西,所以让我们这样做吧。

    function flattenSectionsAndSubs(item) {
        return {
            type: item.type, 
            subs: item.sections.reduce((acc, cur) => ([...acc, ...cur.sub]), [])
        }; 
    }
    

    我将复制粘贴该分区函数:

    function partition(array, isValid) {
      return array.reduce(([pass, fail], elem) => {
        return isValid(elem) ? [[...pass, elem], fail] : [pass, [...fail, elem]];
      }, [[], []]);
    }
    
    
        const listTypes = ['ordered-item', 'unordered-item']; 
        function createEmbeddedFromItem(item) {
            const [lists, nonLists] = partition(item.subs, (v) => listTypes.includes(v.type); 
    
          return {
             type: item.type, 
             embedded: [
                 ...nonLists, 
                 {
                    type: "list", 
                    items: lists
                 }
             ]
          }
        }
    
    

    把这一切放在一起,我们就得到了。

    const contentData = {
      data: {
        content: [{
            type: "column",
            sections: [{
              sub: [{
                type: "heading-1",
                text: "Heading Text"
              }]
            }]
          },
          {
            type: "acc-item",
            sections: [{
              sub: [{
                  type: "heading-1",
                  text: "Heading Text"
                },
                {
                  type: "ordered-item",
                  text: "Item 1"
                },
                {
                  type: "unordered-item",
                  text: "Item 2"
                }
              ]
            }]
          },
          {
            type: "acc-item",
            sections: [{
              sub: [{
                type: "heading-1",
                text: "Heading Text 2"
              }]
            }]
          }
        ]
      }
    }
    
    
    function partition(array, isValid) {
      return array.reduce(([pass, fail], elem) => {
        return isValid(elem) ? [
          [...pass, elem], fail
        ] : [pass, [...fail, elem]];
      }, [
        [],
        []
      ]);
    }
    
    
    function flattenSectionsAndSubs(item) {
      return {
        type: item.type,
        subs: item.sections.reduce((acc, cur) => ([...acc, ...cur.sub]), [])
      };
    }
    
    const listTypes = ['ordered-item', 'unordered-item'];
    
    function createEmbeddedFromItem(item) {
      const [lists, nonLists] = partition(item.subs, (v) => listTypes.includes(v.type));
    
        return {
          type: item.type,
          embedded: [
            ...nonLists,
            {
              type: "list",
              items: lists
            }
          ]
        }
      }
    
    
      const groupedData = contentData.data.content.reduce((acc, cur) => {
        //Check if this indexed array already exists, if not create it. 
        const currentArray = (acc[`${cur.type}-group`] && acc[`${cur.type}-group`].items) || [];
    
        const flattenedItem = flattenSectionsAndSubs(cur);
        const embeddedItem = createEmbeddedFromItem(flattenedItem);
        return {
          ...acc,
          [`${cur.type}-group`]: {
              type: `${cur.type}-group`, 
              items: [...currentArray, embeddedItem]
          }
        }
      }, {});
    
      console.log(groupedData);

    现在这与您所要求的不完全匹配 - 但它应该可以工作。

    如果数组不为空,您可以将自己的位添加到仅添加列表项中,并阻止列在其自己的组中。

    问题是 - tbh 似乎有点危险,您将创建一个没有匹配结构的项目数组,这就是我这样做的原因。

    【讨论】:

    • in flattenSectionsAndSubs .flat dosent 在 IE 中工作
    • 在此处查看此答案:stackoverflow.com/questions/38696119/… 您可能想使用 polyfill,或使用 babel 编译生产代码,或稍微更改语法。
    • 我在这里复制了代码,以便使用 babel 编译 - 看看它在那里工作:codepen.io/dwjohnston/pen/KLBwza?editors=1111
    • 我可以看到结果中添加了一个空的list
    • @user007 是的。看我最后的cmets。您可以自己编辑代码以使其完全按照您的意愿进行操作。我已经向您展示了一般流程。
    猜你喜欢
    • 2019-04-23
    • 1970-01-01
    • 2020-12-21
    • 2022-11-25
    • 2021-11-28
    • 1970-01-01
    • 2019-10-06
    • 1970-01-01
    • 2021-06-07
    相关资源
    最近更新 更多