如何通过某个属性的值将元素数组拆分为组?

时间:2019-10-08 09:35:04

标签: javascript typescript

我有一个数组:

[{
    name: "A1"
    series: "A series"
}, 
{
    name: "A2"
    series: "A series"
}, 
{
    name: "B1"
    series: "B series"
}, 
{
    name: "C1"
    // series is not defined
}]

我想将此数组拆分为多个数组,这些数组按series属性的值分组。我想得出以下结构。但是,只要结果包含按其series属性值分组的数组,确切的格式就无关紧要。

[
    {
        series: "A series",
        items: [{
            name: "A1"
        },
        {
            name: "A2"
        }]
    },
    {
        series: "B series",
        items: [{
            name: "B1"
        }]
    }
    {
        items: [{
            name: "C1"
        }]
    }
]

这是我的最佳尝试:

private groupProductsBySeries = (devices: IItem[]): IProductGroup[] => {
    const seriesSymbols: any = new Map();
    const itemsBySeries: any = [];
    const series: any = [];

    devices.forEach((device) => {
        let symbol = seriesSymbols.get(device.properties.series);
        if (!symbol) {
            symbol = Symbol();
            seriesSymbols.set(device.properties.series, symbol);
        }

        Array.isArray(itemsBySeries[symbol])
            ? itemsBySeries[symbol].push(device)
            : (itemsBySeries[symbol] = [device]);
    });

    seriesSymbols.forEach((value: any, key: any) => {
        series.push({
            name: key,
            items: itemsBySeries[value],
        });
    });

    return series;
};

我在想,也许这是不必要的复杂。当我尝试添加类型时,我会收到TypeScript编译器的抱怨。

问题:

  • 是否有更好的方法来解决此问题?
  • 如果不是,那么上面添加成功添加类型的代码的外观如何? 如果不是

在adigas评论后编辑

3 个答案:

答案 0 :(得分:1)

function groupProductsBySeries(devices) {
  const series = Array.from(new Set(devices.map(item => item.series)));
  return series.map(item => {
    const series = item ? { series: item } : null;

    return {
      ...series,
      items: devices.filter(device => device.series === item)
    };
  });
}

答案 1 :(得分:-1)

您可以编写一个通用函数来接受任何字段并按它们分组。诸如此类的内容可能会有所帮助。

data = [{
    name: "A1",
    series: "A series"
}, 
{
    name: "A2",
    series: "A series"
}, 
{
    name: "B1",
    series: "B series"
}, 
{
    name: "C1",
    // series is not defined
}]

data1 = [{
    name: "A",
    series: "A series"
}, 
{
    name: "A",
    series: "A series"
}, 
{
    name: "B",
    series: "B series"
}, 
{
    name: "C",
    // series is not defined
}]


function groupByField(data, field){
    const groupedByObject = data.reduce((acc, val) => {
        const rest = Object.keys(val).reduce((newObj, key) => {
            if(key !== field){
                newObj[key] = val[key]
            }
            return newObj;
        }, {});
        if (acc[val[field]]) {
          acc[val[field]].push(rest);
        } else {;
          acc[val[field]] = [rest];
        }
        return acc;
    }, {})

    //Return the reduced object from above if want in Object format. If wanted array, return the below statement

    return Object.keys(groupedByObject).filter(a => a!== "undefined").map(key => ({[field]: key, items: groupedByObject[key]}))

}

a = groupByField(data,"series");
console.log("Grouped by series")
console.log(a);



b = groupByField(data1, "name");
console.log("Grouped by name")
console.log(b);

答案 2 :(得分:-1)

我将遍历每个对象的nameseries属性,如果series默认为空字符串(如果为空),则将值放在其属性为{ {1}}被迭代,并且该系列的关联对象(带有嵌套的series数组)。如果尚不存在序列,请根据需要创建它(并在必要时分配一个items属性),否则只需将series推入该序列即可。

最后,获取对象的值以获得所需的输出:

{ name }

翻译成Javascript:

const arr = [
    {
        name: 'A1',
        series: 'A series',
    },
    {
        name: 'A2',
        series: 'A series',
    },
    {
        name: 'B1',
        series: 'B series',
    },
    {
        name: 'C1',
    // series is not defined
    },
];
type outputItem = {
    series?: string,
    items: Array<{ name: string }>,
};
const groupedObj: { [series: string]: outputItem } = {};
for (const { name, series='' } of arr) {
    if (!groupedObj[series]) {
        groupedObj[series] = { items: [{ name }] };
        if (series) {
            groupedObj[series].series = series;
        }
    } else {
        groupedObj[series].items.push({ name });
    }
}
const output = Object.values(groupedObj);
console.log(output);

不过,该对象结构非常独特。使用键为"use strict"; const arr = [ { name: 'A1', series: 'A series', }, { name: 'A2', series: 'A series', }, { name: 'B1', series: 'B series', }, { name: 'C1', }, ]; const groupedObj = {}; for (const { name, series = '' } of arr) { if (!groupedObj[series]) { groupedObj[series] = { items: [{ name }] }; if (series) { groupedObj[series].series = series; } } else { groupedObj[series].items.push({ name }); } } const output = Object.values(groupedObj); console.log(output);且值是series值数组的单个对象可能会容易得多:

name

翻译成Javascript:

const arr = [
    {
        name: 'A1',
        series: 'A series',
    },
    {
        name: 'A2',
        series: 'A series',
    },
    {
        name: 'B1',
        series: 'B series',
    },
    {
        name: 'C1',
    // series is not defined
    },
];
const output: { [series: string]: string[] } = {};
for (const { name, series='' } of arr) {
    if (!output[series]) {
        output[series] = [name];
    } else {
        output[series].push(name);
    }
}
console.log(output);