从多个嵌套数组创建新的数据对象集

时间:2019-05-28 01:43:22

标签: javascript arrays typescript multidimensional-array

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

下面是当前结构

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

2 个答案:

答案 0 :(得分:1)

您可以存储最后一个项目数组以及最后一个嵌入式数组,并使用它们直到找到列类型为止。

   id_command command_status    stage  line_amount  global_amount  decision
0          61        ZeFMAA1  Pending       582.96         582.96     False
1          61       UbUjNAAV  Pending     70481.00         582.96     False
2         945      0bR8hEQAS  Pending      6400.00       12800.00      True
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);

答案 1 :(得分:0)

Array.prototypeObject.prototype方法非常适合这种情况。

您是对的,这是某种复杂的逻辑。

我建议您为此绝对需要一些单元测试,然后尝试将其分开。

这就是我想做的方式。

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

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

我快速搜索了“ 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->类型并将它们过滤成两个数组。快速的Google如何使用过滤器创建两个数组给了我this answer.

不过,首先,我们需要将sections-> 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);

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

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

问题是-似乎您会创建一个没有匹配结构的项目数组,这有点危险,这就是为什么我这样做了。