对Javascript数组进行分组

时间:2017-01-27 16:08:36

标签: javascript arrays lodash

我正在尝试从一个数组中获取数据,按对象属性对数据进行分组,然后将其发送到新数组。目前的数据格式如下:

const data = [
    {
        "dataId": "1",
        "tableName": "table1",
        "column": "firstHeader",
        "rows": [
            "a","b","c"
        ]
    },
    {
        "dataId": "2",
        "tableName": "table1",
        "column": "secondHeader",
        "rows": [
            "d","e","f",
        ]
    },
    {
        "dataId": "3",
        "tableName": "table2",
        "column": "aNewFirstHeader",
        "rows": [
            1,2,3
        ]
    }
];

我使用了Lodash groupby方法,该方法以一种接近我期望的格式对项目进行分组,但不完全是我想要的最终结果。 lodash结果是:

[
    [
        { "tableName": 'table1',
            "dataId": '1',
            "header": 'firstHeader',
            "rows": ["a","b","c"]
        },

        { "tableName": 'table1',
            "dataId": '1',
            "header": 'secondHeader',
            "rows": ["d","e","f"]
        }
    ],

    [
        { "tableName": 'table2',
            "dataId": '2',
            "header": 'aNewFirstHeader',
            "rows": [1,2,3] },
    ]
]

最终,我要找的是最终结果:

[
    {
    "tableName": "table1",
    "column": ["firstHeader", "secondHeader"],
    "rows": [["a","b","c"], ["d","e","f"]]
    },
    {
    "tableName": "table2",
    "column": ["aNewFirstHeader"],
    "rows": [[1,2,3]]
    }
]

有没有不同的方法来使用groupBy方法,或者可能只使用javascript方法来获得我想要的最终结果?

8 个答案:

答案 0 :(得分:1)

通过使用reducefindIndex,我们可以在O(n)时间内重建适合您格式的新数组。

data.reduce((arr, record) => {
  const index = arr.findIndex((inside) => (inside.tableName === record.tableName));

  if (index === -1) { 
    arr.push({
        tableName: record.tableName,
        column: [record.column],
        rows: [record.rows]
    }) 
  } else {
    arr[index].column.push(record.column);
    arr[index].rows.push(record.rows);
  }

  return arr;
}, []);



const data = [
{
    "dataId": "1",
    "tableName": "table1",
    "column": "firstHeader",
    "rows": [
        "a", "b", "c"
    ]
},
{
    "dataId": "2",
    "tableName": "table1",
    "column": "secondHeader",
    "rows": [
        "d", "e", "f",
    ]
},
{
    "dataId": "3",
    "tableName": "table2",
    "column": "aNewFirstHeader",
    "rows": [
        1, 2, 3
    ]
}
];

const newData = data.reduce((arr, record) => {
  const index = arr.findIndex((inside) => (inside.tableName === record.tableName));

  if (index === -1) { 
	arr.push({
        tableName: record.tableName,
		column: [record.column],
		rows: [record.rows]
	}) 
  } else {
	arr[index].column.push(record.column);
    arr[index].rows.push(record.rows);
  }
  return arr;

}, []);

console.log(newData);




答案 1 :(得分:0)

试试这个,仅使用普通香草js:

var merge = function( data){
        var outputArray = [], enteredNames = [];
        for(var i=0; i<data.length; i++){
            var datum = data[i];
            var ownElement;
            if(enteredNames.indexOf(datum.tableName)>-1)
                ownElement = outputArray[enteredNames.indexOf(datum.tableName)];
            else
                {
                ownElement = {

                    "tableName": datum.tableName,
                    "column": [],
                    "rows": []

                    }
                enteredNames.push( datum.tableName ); 
                outputArray.push( ownElement );
                }

            ownElement.column.push( datum.column );
            ownElement.rows.push( datum.rows );

        }
        return outputArray;
}

答案 2 :(得分:0)

使用内置的JavaScript数组原型方法mapreduce来简化您的问题:

const data = [
    {
        "dataId": "1",
        "tableName": "table1",
        "column": "firstHeader",
        "rows": [
            "a", "b", "c"
        ]
    },
    {
        "dataId": "2",
        "tableName": "table1",
        "column": "secondHeader",
        "rows": [
            "d", "e", "f",
        ]
    },
    {
        "dataId": "3",
        "tableName": "table2",
        "column": "aNewFirstHeader",
        "rows": [
            1, 2, 3
        ]
    }
];

const EXPECTED = [
    {
        "tableName": "table1",
        "column": ["firstHeader", "secondHeader"],
        "rows": [["a", "b", "c"], ["d", "e", "f"]]
    },
    {
        "tableName": "table2",
        "column": ["aNewFirstHeader"],
        "rows": [[1, 2, 3]]
    }
];

var result = data
    .reduce((hash, dataItem) => {
        // first group by tableName
        if (hash[dataItem.tableName]) {
            hash[dataItem.tableName].column.push(dataItem.column);
            hash[dataItem.tableName].rows.push(dataItem.rows);
        } else {
            hash[dataItem.tableName] = {
                column: [dataItem.column],
                rows: [dataItem.rows]
            };
        }

        return hash;
    }, {});

// run a map to change to the exact array style you want
result = Object.keys(result).map((tableName) => {
    return {
        tableName: tableName,
        column: result[tableName].column,
        rows: result[tableName].rows
    };
});

// if in a node environment, you can assert (for unit testing only)
require('assert').deepStrictEqual(result, EXPECTED);

答案 3 :(得分:0)

jsFiddle

const data = [
    {
        "dataId": "1",
        "tableName": "table1",
        "column": "firstHeader",
        "rows": [
            "a","b","c"
        ]
    },
    {
        "dataId": "2",
        "tableName": "table1",
        "column": "secondHeader",
        "rows": [
            "d","e","f",
        ]
    },
    {
        "dataId": "3",
        "tableName": "table2",
        "column": "aNewFirstHeader",
        "rows": [
            1,2,3
        ]
    }
];

var result = _.chain(data)
    .groupBy("tableName")
    .pairs()
    .map(function (currentItem) {
        // used to create desired properties
        var rows = [];
        var columns = [];
        // loop to fill values
        for(var i=0,length=currentItem[1].length;i<length;i++){
          columns.push(currentItem[1][i].column)
          rows = rows.concat(currentItem[1][i].rows);
        }
        return {
          'tableName': currentItem[0],
          'column': columns,
          'rows': rows
        };
    })
    .value();
console.log(result);

答案 4 :(得分:0)

编辑:哦,我完全忘记.findIndex()是一件事。这是更新的解决方案:

使用.map().reduce()&amp; .findIndex()

const newArr = data.map(value => ({
        tableName: value.tableName,
        column: [value.column],
        rows: [value.rows],
    }))
    .reduce((acc, cur) => {
        const tableNameIndex = acc.findIndex(el => el.tableName === cur.tableName);
        if (tableNameIndex !== -1) {
            acc[tableNameIndex].column.push(cur.column[0]);
            acc[tableNameIndex].rows.push(cur.rows[0]);
            return acc;
        } else {
            acc.push(cur);
            return acc;
        }
    }, [])

console.log(newArr);

答案 5 :(得分:0)

使用+---------+------------+-----------------------------+-----------------------------+ | Line Operation | StartDate | EndDate | +---------+------------+-----------------------------+-----------------------------+ | ACOE | OP10 | 2017-01-27 10:00:00.000 | 2017-01-27 11:10:00.000 | | ACOE | OP20 | 2017-01-27 11:10:00.000 | 2017-01-27 11:25:00.000 | | ACOE | OP30 | 2017-01-27 12:10:00.000 | 2017-01-27 12:25:00.000 | +---------+------------+-----------------------------+-----------------------------+ 使用_.groupBy()映射每个组以将组中的所有对象组合到新对象后,将除_.mergeWith()之外的所有内容推送到数组中。然后使用tableName删除_.omit()

&#13;
&#13;
dataId
&#13;
const data = [{"dataId":"1","tableName":"table1","column":"firstHeader","rows":["a","b","c"]},{"dataId":"2","tableName":"table1","column":"secondHeader","rows":["d","e","f"]},{"dataId":"3","tableName":"table2","column":"aNewFirstHeader","rows":[1,2,3]}];

const result = _(data)
  .groupBy('tableName')
  .map((group) => // map each group
       // remove the dataId property
    _.omit( 
      // merge all group objects
      _.mergeWith({}, ...group, (objValue = [], srcValue, key) => {
        // if the key is not tableName push it into the array
        if (key !== 'tableName') {
          objValue.push(srcValue);
          return objValue;
        }
      }),
      'dataId'))
  .value();

console.log(result);
&#13;
&#13;
&#13;

答案 6 :(得分:0)

普通Javascript:

function groupBy(data, fieldName) {
    var groups = {}
    for (var i=0; i<data.length; i++) {
        var elem = data[i];
        if (fieldName in elem) {
            var fieldVal = elem[fieldName];
            if (!(fieldVal in groups)) {
                groups[fieldVal] = [];
            }
            groups[fieldVal].push(elem)
        }
    }
    var result = [];
    for (list in groups) {
        var arr = groups[list];
        var combine = {}
        combine[fieldName] = arr[0][fieldName];
        for (var i=0; i<arr.length; i++) {
            var elem = arr[i];
            for (prop in elem) {
                if (prop == fieldName) {
                    continue;
                }
                if (!(prop in combine)) {
                    combine[prop] = [];
                }
                combine[prop].push(elem[prop]);
            }
        }
        result.push(combine);
    }
    return result;
}

对于您的情况,只需调用:

groupBy(data, "tableName")

答案 7 :(得分:0)

在普通的Javascript中,您可以使用Map

&#13;
&#13;
var data = [{ dataId: "1", tableName: "table1", column: "firstHeader", rows: ["a", "b", "c"] }, { dataId: "2", tableName: "table1", column: "secondHeader", rows: ["d", "e", "f", ] }, { dataId: "3", tableName: "table2", column: "aNewFirstHeader", rows: [1, 2, 3] }],
    result = data.reduce((map => (r, a) => {
        var item = map.get(a.tableName);
        if (!item) {
            item = { tableName: a.tableName, column: [], rows: [] }
            map.set(a.tableName, item);
            r.push(item);
        }
        item.column.push(a.column);
        item.rows.push(a.rows);
        return r;
    })(new Map), []);

console.log(result);
&#13;
.as-console-wrapper { max-height: 100% !important; top: 0; }
&#13;
&#13;
&#13;