Javascript按特定顺序按多个属性递归地分组和数组

Javascript按特定顺序按多个属性递归地分组和数组,javascript,ecmascript-6,grouping,Javascript,Ecmascript 6,Grouping,我正在构建一个网格组件,允许用户进行多行分组 我正在处理的原始数据是库存项目的示例: let stock = [ { order: "200", type: "production", qty: 200, item: "IT282" }, { order: "200", type: "production", qty: 90, item: "IT283" }, { order: "200", type: "customer", qty: 80, item: "IT102"

我正在构建一个网格组件,允许用户进行多行分组

我正在处理的原始数据是库存项目的示例:

let stock = [
    { order: "200", type: "production", qty: 200, item: "IT282" },
    { order: "200", type: "production", qty: 90, item: "IT283" },
    { order: "200", type: "customer", qty: 80, item: "IT102" },
    { order: "200", type: "production", qty: 110, item: "IT283" },
    { order: "200", type: "customer", qty: 130, item: "IT102" },
    { order: "200", type: "production", qty: 45, item: "IT233" },
    { order: "200", type: "stock", qty: 30, item: "IT282" },
    { order: "210", type: "production", qty: 300, item: "IT282" },
    { order: "210", type: "production", qty: 190, item: "IT283" },
    { order: "210", type: "customer", qty: 180, item: "IT102" },
    { order: "210", type: "production", qty: 210, item: "IT283" },
    { order: "210", type: "customer", qty: 230, item: "IT102" },
    { order: "210", type: "production", qty: 145, item: "IT233" },
    { order: "210", type: "stock", qty: 130, item: "IT282" }
];
我需要完成的是能够使用不同顺序的多个字段对数据进行分组,如以下结果:

let result = groupBy(stock, ["order"]);

[
    {
        field: "order",
        value: "200",
        rows: [
            { order: "200", type: "production", qty: 200, item: "IT282" },
            { order: "200", type: "production", qty: 90, item: "IT283" },
            { order: "200", type: "customer", qty: 80, item: "IT102" },
            { order: "200", type: "production", qty: 110, item: "IT283" },
            { order: "200", type: "customer", qty: 130, item: "IT102" },
            { order: "200", type: "production", qty: 45, item: "IT233" },
            { order: "200", type: "stock", qty: 30, item: "IT282" }
        ]
    },
    {
        field: "order",
        value: "210",
        rows: [
            { order: "210", type: "production", qty: 300, item: "IT282" },
            { order: "210", type: "production", qty: 190, item: "IT283" },
            { order: "210", type: "customer", qty: 180, item: "IT102" },
            { order: "210", type: "production", qty: 210, item: "IT283" },
            { order: "210", type: "customer", qty: 230, item: "IT102" },
            { order: "210", type: "production", qty: 145, item: "IT233" },
            { order: "210", type: "stock", qty: 130, item: "IT282" }
        ]
    }
];

let result = groupBy(stock, ["item"]);

[
    {
        field: "item",
        value: "IT282",
        rows: [
            { order: "200", type: "production", qty: 200, item: "IT282" },
            { order: "200", type: "stock", qty: 30, item: "IT282" },
            { order: "210", type: "production", qty: 300, item: "IT282" },
            { order: "210", type: "stock", qty: 130, item: "IT282" }
        ]
    },
    {
        field: "item",
        value: "IT283",
        rows: [
            { order: "200", type: "production", qty: 90, item: "IT283" },
            { order: "200", type: "production", qty: 110, item: "IT283" },
            { order: "210", type: "production", qty: 190, item: "IT283" },
            { order: "210", type: "production", qty: 210, item: "IT283" }
        ]
    },
    {
        field: "item",
        value: "IT102",
        rows: [
            { order: "200", type: "customer", qty: 80, item: "IT102" },
            { order: "200", type: "customer", qty: 130, item: "IT102" },
            { order: "210", type: "customer", qty: 180, item: "IT102" },
            { order: "210", type: "customer", qty: 230, item: "IT102" }
        ]
    },
    {
        field: "item",
        value: "IT233",
        rows: [
            { order: "200", type: "production", qty: 45, item: "IT233" },
            { order: "210", type: "production", qty: 145, item: "IT233" }
        ]
    }
];

let result = groupBy(stock, ["order", "item"]);

[
    {
        field: "order",
        value: "200",
        rows: [
            {
                field: "item",
                value: "IT282",
                rows: [
                    {
                        order: "200",
                        type: "production",
                        qty: 200,
                        item: "IT282"
                    },
                    { order: "200", type: "stock", qty: 30, item: "IT282" },
                    {
                        order: "210",
                        type: "production",
                        qty: 300,
                        item: "IT282"
                    }
                ]
            },
            {
                field: "item",
                value: "IT283",
                rows: [
                    {
                        order: "200",
                        type: "production",
                        qty: 90,
                        item: "IT283"
                    },
                    {
                        order: "200",
                        type: "production",
                        qty: 110,
                        item: "IT283"
                    }
                ]
            },
            {
                field: "item",
                value: "IT102",
                rows: [
                    { order: "200", type: "customer", qty: 80, item: "IT102" },
                    { order: "200", type: "customer", qty: 130, item: "IT102" }
                ]
            },
            {
                field: "item",
                value: "IT233",
                rows: [
                    {
                        order: "200",
                        type: "production",
                        qty: 45,
                        item: "IT233"
                    }
                ]
            }
        ]
    },
    {
        field: "order",
        value: "210",
        rows: [
            {
                field: "item",
                value: "IT282",
                rows: [{ order: "210", type: "stock", qty: 130, item: "IT282" }]
            },
            {
                field: "item",
                value: "IT283",
                rows: [
                    {
                        order: "210",
                        type: "production",
                        qty: 190,
                        item: "IT283"
                    },
                    {
                        order: "210",
                        type: "production",
                        qty: 210,
                        item: "IT283"
                    }
                ]
            },
            {
                field: "item",
                value: "IT102",
                rows: [
                    { order: "210", type: "customer", qty: 180, item: "IT102" },
                    { order: "210", type: "customer", qty: 230, item: "IT102" }
                ]
            },
            {
                field: "item",
                value: "IT233",
                rows: [
                    {
                        order: "210",
                        type: "production",
                        qty: 145,
                        item: "IT233"
                    }
                ]
            }
        ]
    }
];

let result = groupBy(stock, ["item", "order"]);

[
    {
        field: "item",
        value: "IT282",
        rows: [
            {
                field: "order",
                value: "200",
                rows: [
                    {
                        order: "200",
                        type: "production",
                        qty: 200,
                        item: "IT282"
                    },
                    { order: "200", type: "stock", qty: 30, item: "IT282" }
                ]
            },
            {
                field: "order",
                value: "210",
                rows: [
                    {
                        order: "210",
                        type: "production",
                        qty: 300,
                        item: "IT282"
                    },
                    { order: "210", type: "stock", qty: 130, item: "IT282" }
                ]
            }
        ]
    },
    {
        field: "item",
        value: "IT283",
        rows: [
            {
                field: "order",
                value: "200",
                rows: [
                    {
                        order: "200",
                        type: "production",
                        qty: 90,
                        item: "IT283"
                    },
                    {
                        order: "200",
                        type: "production",
                        qty: 110,
                        item: "IT283"
                    }
                ]
            },
            {
                field: "order",
                value: "210",
                rows: [
                    {
                        order: "210",
                        type: "production",
                        qty: 190,
                        item: "IT283"
                    },
                    {
                        order: "210",
                        type: "production",
                        qty: 210,
                        item: "IT283"
                    }
                ]
            }
        ]
    },
    {
        field: "item",
        value: "IT102",
        rows: [
            {
                field: "order",
                value: "200",
                rows: [
                    { order: "200", type: "customer", qty: 80, item: "IT102" },
                    { order: "200", type: "customer", qty: 130, item: "IT102" }
                ]
            },
            {
                field: "order",
                value: "210",
                rows: [
                    { order: "210", type: "customer", qty: 180, item: "IT102" },
                    { order: "210", type: "customer", qty: 230, item: "IT102" }
                ]
            }
        ]
    },
    {
        field: "item",
        value: "IT233",
        rows: [
            {
                field: "order",
                value: "200",
                rows: [
                    { order: "200", type: "production", qty: 45, item: "IT233" }
                ]
            },
            {
                field: "order",
                value: "210",
                rows: [
                    {
                        order: "210",
                        type: "production",
                        qty: 145,
                        item: "IT233"
                    }
                ]
            }
        ]
    }
];
My group函数将接收任意项目数组,并按任意顺序对任意数量的数组字段进行分组

因为我想要一个基于ES6的函数,所以今天我使用了下面的
groupBy
函数,该函数只适用于一个过程,但是我很难将它们嵌套在一起

以下是我正在编写的代码:

  groupBy = (rows, groups) => {
    if (groups.length === 0) return rows;

    return this.groupByField(rows, groups, 0);
  };

  groupByField = (rows, groups, index) => {
    if (index >= groups.length) return rows;

    let grouped = this.groupRows(rows, groups[index]);

    index++;
    let ret = [];

    grouped.rows.map(row => {
      ret.push(this.groupByField(row.rows, groups, index));
    });

    grouped.rows = ret;
    return grouped;
  };

  groupRows = (rows, field) => {
    return rows.reduce(function(groups, x) {
      let val = helper.getValueByFieldNameString(x.data, field);

      let found = groups.find(item => {
        return item.groupedValue === val;
      });

      if (!found) {
        let rows = [];
        rows.push(x);

        groups.push({
          groupedField: field,
          groupedValue: val,
          rows: rows
        });
      } else {
        found.rows.push(x);
      }

      return groups;
    }, []);
  };

似乎递归性工作不正常。

我认为您可以使用
reduce
Object.values
创建一个函数,对数组进行分组。然后,在对数组进行分组后,如果有更多字段要分组,则对每个子
数组调用函数。例如:

let stock=[{订单:“200”,类型:“生产”,数量:200,项目:“IT282”},{订单:“200”,类型:“生产”,数量:90,项目:“IT283”},{订单:“200”,类型:“客户”,数量:80,项目:“IT102”},{订单:“200”,类型:“生产”,数量:110,项目:“IT283”},{订单:“200”,类型:“客户”,数量:130,项目:“IT102”},{订单:“200”,类型:“生产”,数量:45,项目:“IT233”},{订单:“200”,类型:“库存”,数量:30,项目:“IT282”},{订单:“210”,类型:“生产”,数量:300,项目:“IT282”},{订单:“210”,类型:“生产”,数量:190,项目:“IT283”},{订单:“210”,类型:“客户”,数量:180,项目:“IT102”},{订单:“210”,类型:“生产”,数量:210,项目:“IT283”},{订单:“210”,类型:“客户”,数量:230,项目:“IT102”},{订单:“210”,类型:“生产”,数量:145,项目:“IT233”},{订单:“210”,类型:“库存”,数量:130,项目:“IT282”};
功能分组依据(arr,字段){
let field=fields[0]//一次一个字段
如果(!字段)返回arr
让retArr=Object.values(
arr.reduce((obj,电流)=>{
如果(!obj[current[field]])obj[current[field]={field:field,value:current[field],rows:[]}
obj[当前[字段]].行.推送(当前)
返回obj
}, {}))
//如果还有剩余字段,则对每个子行递归
if(字段长度){
重新分配forEach(对象=>{
obj.count=obj.rows.length
obj.rows=groupBy(obj.rows,fields.slice(1))
})
}
回程复飞
}
let result=groupBy(库存,[“订单”,“项目]);

console.log(result)
我认为您可以使用
reduce
Object.values
创建一个函数来对数组进行分组。然后在对数组进行分组后,如果您有更多字段要分组,请对每个子
数组调用该函数。例如:

let stock=[{订单:“200”,类型:“生产”,数量:200,项目:“IT282”},{订单:“200”,类型:“生产”,数量:90,项目:“IT283”},{订单:“200”,类型:“客户”,数量:80,项目:“IT102”},{订单:“200”,类型:“生产”,数量:110,项目:“IT283”},{订单:“200”,类型:“客户”,数量:130,项目:“IT102”},{订单:“200”,类型:生产,数量:45,项目:“IT233”},{订单:“200”,类型:“库存”,数量:30,项目:“IT282”},{订单:“210”,类型:“生产”,数量:300,项目:“IT282”},{订单:“210”,类型:“生产”,数量:190,项目:“IT283”},{订单:“210”,类型:“客户”,数量:180,项目:“IT102”},{订单:“210”,类型:“生产”,数量:210,项目:“IT283”},{订单:210“,类型:“客户”,数量:230,项目:“IT102”},{订单:“210”,类型:“生产”,数量:145,项目:“IT233”},{订单:“210”,类型:“库存”,数量:130,项目:“IT282”});
功能分组依据(arr,字段){
let field=fields[0]//一次一个字段
如果(!字段)返回arr
让retArr=Object.values(
arr.reduce((obj,电流)=>{
如果(!obj[current[field]])obj[current[field]={field:field,value:current[field],rows:[]}
obj[当前[字段]].行.推送(当前)
返回obj
}, {}))
//如果还有剩余字段,则对每个子行递归
if(字段长度){
重新分配forEach(对象=>{
obj.count=obj.rows.length
obj.rows=groupBy(obj.rows,fields.slice(1))
})
}
回程复飞
}
let result=groupBy(库存,[“订单”,“项目]);

console.log(结果)
你为什么删除前一个?@Ankit,前一个错误,编辑时我得到了2张反对票……你为什么删除前一个?@Ankit,前一个错误,编辑时我得到了2张反对票……谢谢Mark的帖子。我正在尝试你发布的代码,目前它工作正常。我不会一直在建我的表格从结果来看,我怎么知道,在渲染行时,哪些列要执行rowSpan,以及有多少行?嗨@Mendes,代码中实际上有一个bug,我想我已经修复了。我还对它进行了编辑,在每个项中添加了一个
计数
,它将是一个节点的所有后代的总和,这只是递归之前的行长度。我nk这就是你想要的计数。非常好的一段代码。感谢@Mark的版本和我的额外要求……做得好。还有一个问题。我如何向每一行添加它分组的递归字段?在示例中,最后一个示例应该在每一行上显示它是按
字段和
顺序以及元素的数量。这是使用html构建结果表时进行colSpan操作所必需的。感谢您的帮助!感谢Mark的帖子。我正在尝试您发布的代码,目前它工作正常。我并不坚持根据结果构建表。在呈现行时,我如何知道哪些列要进行rowSpan操作以及有多少行?H我@Mendes,代码中实际上有一个bug,我想我已经修复了。我还对它进行了编辑,在每个项目中添加了一个
count
,这将是所有描述的总和