筛选多个对象数组

Filter multiple arrays of objects

本文关键字:数组 对象 筛选      更新时间:2023-09-26

我有以下情况:

数组的数量未定义。每个数组都包含一些对象。这些对象中的每一个都有一个 id 元素,以及其他一些元素。

//Example objects:
f = [{'id': 1, 'name': 'a'}, {'id': 2, 'name': 'b'},
     {'id': 3, 'name': 'c'}, {'id': 1, 'name': 'd'}, ...]
g = [{'id': 2, 'name': 'e'}, {'id': 4, 'name': 'f'}, 
     {'id': 3, 'name': 'g'}, {'id': 4, 'name': 'h'}, ...]
h = ...
i = ...

我想过滤掉所有重复项,不仅在每个单独的数组中,而且在不同的数组中

编辑:当两个对象的id元素相同时,它们是重复的。优先级无关紧要,第一次出现就可以了。

我想出了以下功能:

function uniqueObjects() {
    var seen = [];
    for (var i=0; i<arguments.length; i++) {
        var arg = arguments[i];
        for (var j=0; j<arg.length; j++) {
            var elm = arg[j];
            var key = elm['id'];
            if (seen.indexOf(key) > -1) {
                arg.pop(elm);
            } else {
                seen.push(key);
            }
        }
    }
    return arguments;
}

但这似乎无法正常工作,因为我得到了以下值:

{'0': [{'id': 1, 'name': 'a'}, 
       {'id': 2, 'name': 'b'}, 
       {'id': 3, 'name': 'c'}], 
 '1': [{'id': 2, 'name': 'e'}, 
       {'id': 4, 'name': 'f'}]}

主要问题在这里:

arg.pop(elm);

pop 删除数组中的最后一个元素,并且不接受任何参数。您可能的意思是:

arg.splice(j, 1);

。但是,如果您这样做,则不需要增加j。因此,这给了我们:

function uniqueObjects() {
    var seen = [];
    for (var i=0; i<arguments.length; i++) {
        var arg = arguments[i];
        var j = 0;                       // **
        while (j<arg.length) {           // ** Made this a while loop
            var elm = arg[j];
            var key = elm['id'];
            if (seen.indexOf(key) > -1) {
                arg.splice(j, 1);         // ** Remove this entry
            } else {
                seen.push(key);
                ++j;                      // ** Increment j
            }
        }
    }
    return arguments;
}

但是,有一种更有效的方法来跟踪您看到的id值: 使用对象:

function uniqueObjects() {
    var seen = {};
    for (var i=0; i<arguments.length; i++) {
        var arg = arguments[i];
        var j = 0;
        while (j<arg.length) {
            var elm = arg[j];
            var key = " " + elm['id'];    // ** Note the space
            if (seen[key]) {              // ** Updated check
                arg.splice(j, 1);
            } else {
                seen[key] = true;         // ** Set the flag
                ++j;
            }
        }
    }
    return arguments;
}

创建key时为什么要将空格放在id之前?如果您id具有存在于对象(如 toStringvalueOf)上的名称的值。(ES6 将引入Map对象,我们不必再这样做了。

我还建议不要返回伪数组arguments,而是使用真实数组。所以:

function uniqueObjects() {
    var seen = {};
    var args = Array.prototype.slice.call(arguments, 0); // <== Make real array
    for (var i=0; i<args.length; i++) {
        var arg = args[i];
        var j = 0;
        while (j<arg.length) {
            var elm = arg[j];
            var key = " " + elm['id'];    // ** Note the space
            if (seen[key]) {              // ** Updated check
                arg.splice(j, 1);
            } else {
                seen[key] = true;         // ** Set the flag
                ++j;
            }
        }
    }
    return args;
}

现场示例:

function uniqueObjects() {
    var seen = {};
    var args = Array.prototype.slice.call(arguments, 0);
    for (var i=0; i<args.length; i++) {
        var arg = args[i];
        var j = 0;
        while (j<arg.length) {
            var elm = arg[j];
            var key = " " + elm['id'];    // ** Note the space
            if (seen[key]) {              // ** Updated check
                arg.splice(j, 1);
            } else {
                seen[key] = true;         // ** Set the flag
                ++j;
            }
        }
    }
    return args;
}
var f = [
  {'id': 1, 'name': 'a'}, {'id': 2, 'name': 'b'},
  {'id': 3, 'name': 'c'}, {'id': 1, 'name': 'd'}
];
var g = [
  {'id': 2, 'name': 'e'}, {'id': 4, 'name': 'f'},
  {'id': 3, 'name': 'g'}, {'id': 4, 'name': 'h'}
];
snippet.log("Before: " + JSON.stringify([f, g]));
var result = uniqueObjects(f, g);
snippet.log("After: " + JSON.stringify(result));
<!-- 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>