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
,这将是所有描述的总和