合并对象数组中的重复对象

Scr*_*ode 17 javascript arrays

我有下面的对象数组,

var data = [
    {
        label: "Book1",
        data: "US edition"
    },
    {
        label: "Book1",
        data: "UK edition"
    },
    {
        label: "Book2",
        data: "CAN edition"
    }
];
Run Code Online (Sandbox Code Playgroud)

我想基于属性'label'合并重复的对象,以便最终输出如下所示,

var data = [
    {
        label: "Book1",
        data: ["US edition", "UK edition"] //data attribute is merged
    },
    {
        label: "Book2",
        data: "CAN edition"
    }
];
Run Code Online (Sandbox Code Playgroud)

有人可以帮我确定方法吗?

T.J*_*der 18

我可能会循环使用filter,沿着这些线跟踪我之前看到的对象的地图(编辑以反映您同意是的,(entry).data总是使数组成为有意义):

var seen = {};
data = data.filter(function(entry) {
    var previous;

    // Have we seen this label before?
    if (seen.hasOwnProperty(entry.label)) {
        // Yes, grab it and add this data to it
        previous = seen[entry.label];
        previous.data.push(entry.data);

        // Don't keep this entry, we've merged it into the previous one
        return false;
    }

    // entry.data probably isn't an array; make it one for consistency
    if (!Array.isArray(entry.data)) {
        entry.data = [entry.data];
    }

    // Remember that we've seen it
    seen[entry.label] = entry;

    // Keep this one, we'll merge any others that match into it
    return true;
});
Run Code Online (Sandbox Code Playgroud)

在ES6环境中,我会使用seen = new Map()而不是seen = {}.

注意:Array.isArray由ES5定义,因此一些相当老的浏览器(如IE8)将无法使用它.它可以轻松地进行垫片/聚合填充,但是:

if (!Array.isArray) {
    Array.isArray = (function() {
        var toString = Object.prototype.toString;
        return function(a) {
            return toString.call(a) === "[object Array]";
        };
    })();
}
Run Code Online (Sandbox Code Playgroud)

旁注:即使我没有看到两个值,我也可能总是创建entry.data一个数组,因为一致的数据结构更容易处理.我之前没有这样做,因为data当只有一个匹配的条目时,你的最终结果显示只是一个字符串. (我们现在已经完成了这个.)

实例(ES5版):

var data = [
    {
        label: "Book1",
        data: "US edition"
    },
    {
        label: "Book1",
        data: "UK edition"
    },
    {
        label: "Book2",
        data: "CAN edition"
    }
];
snippet.log("Before:");
snippet.log(JSON.stringify(data, null, 2), "pre");
var seen = {};
data = data.filter(function(entry) {
    var previous;

    // Have we seen this label before?
    if (seen.hasOwnProperty(entry.label)) {
        // Yes, grab it and add this data to it
        previous = seen[entry.label];
        previous.data.push(entry.data);

        // Don't keep this entry, we've merged it into the previous one
        return false;
    }

    // entry.data probably isn't an array; make it one for consistency
    if (!Array.isArray(entry.data)) {
        entry.data = [entry.data];
    }

    // Remember that we've seen it
    seen[entry.label] = entry;

    // Keep this one, we'll merge any others that match into it
    return true;
});
snippet.log("After:");
snippet.log(JSON.stringify(data, null, 2), "pre");
Run Code Online (Sandbox Code Playgroud)
<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>
Run Code Online (Sandbox Code Playgroud)


小智 7

尝试使用以下方法,它可以找到并且很短

 var data = [
    {
        label: "Book1",
        data: "US edition"
    },
    {
        label: "Book1",
        data: "UK edition"
    },
    {
        label: "Book2",
        data: "CAN edition"
    }
];

const result = Array.from(new Set(data.map(s => s.label)))
    .map(lab => {
      return {
        label: lab,
        data: data.filter(s => s.label === lab).map(edition => edition.data)
      }
    })

console.log(result);
Run Code Online (Sandbox Code Playgroud)