如何删除在对象数组中出现多次的任何对象?

时间:2017-06-21 20:53:02

标签: javascript arrays

如果我有一个类似的数组:

[
    {
        id: 1,
        title: 'foo'
    },
    {
        id: 2,
        title: 'bar'
    },
    {
        id: 3,
        title: 'bat'
    },
    {
        id: 4,
        title: 'bantz'
    },
    {
        id: 2,
        title: 'bar'
    },
    {
        id: 3,
        title: 'bat'
    }
]

我想返回一个包含任何只出现一次的对象的数组。因此,对于此示例,所需的输出将是:

[
    {
        id: 1,
        title: 'foo'
    },
    {
        id: 4,
        title: 'bantz'
    }
]

我尝试过使用reduce()indexOf()解决此问题的一些不同方法,例如this解决方案,但它们不适用于某些对象原因。

非常感谢任何协助。

3 个答案:

答案 0 :(得分:3)

做这样的事情:

const data = [
    {
        id: 1,
        title: 'foo'
    },
    {
        id: 2,
        title: 'bar'
    },
    {
        id: 3,
        title: 'bat'
    },
    {
        id: 4,
        title: 'bantz'
    },
    {
        id: 2,
        title: 'bar'
    },
    {
        id: 3,
        title: 'bat'
    }
];

const isEqual = (a, b) => a.id === b.id;
const unique = (arr) => arr.reduce((result, a, index) =>
  result.concat(arr.some(b => a !== b && isEqual(a, b)) ? [] : a)
, []);

console.log(unique(data));

在这种情况下,我们将每个元素循环到reduce(),在添加之前,我们会在添加之前看到数组中是否存在其他版本的元素。我们必须确保没有自己也不平等(否则我们会得到一个空数组)。

isEqual()是一个单独的功能,可以轻松定制“相等”的含义。

如上所述,data中的每个元素都是唯一的,它们都是独立的对象。 data[0] === data[4]false,即使它们具有相同的数据。您必须比较内部数据以确定它们是否重复。正如Paulpro之前提到的,{} === {}也是false,因为它们是两个不同的对象,即使它们的值相同。

console.log({} === {});
console.log({ a: 1 } === { a: 1 });

isEqual()的示例版本中,如果它们具有相同的ID,我认为它们是相同的。

回答以前版本的问题

做这样的事情:

const data = [
    {
        id: 1,
        title: 'foo'
    },
    {
        id: 2,
        title: 'bar'
    },
    {
        id: 3,
        title: 'bat'
    },
    {
        id: 4,
        title: 'bantz'
    },
    {
        id: 2,
        title: 'bar'
    },
    {
        id: 3,
        title: 'bat'
    }
];

const isEqual = (a, b) => a.id === b.id;
const unique = (arr) => arr.reduce((result, a) =>
  result.concat(result.some(b => isEqual(a, b)) ? [] : a)
, []);

console.log(unique(data));

我将isEqual()拆分为它自己的功能,这样您就可以轻松定义“相等”的含义。有人指出,从技术上讲,即使数据不同,所有这些都是独一无二的。在我的例子中,我将等号id定义为等于。

然后我使用reduce来遍历每个并构建一个对象。在我将它添加到数组之前(通过concat()),我使用some()遍历所有这些并继续直到找到一个相等的(我不会包含)或者没有相等的我加了它。

答案 1 :(得分:3)

您可以使用Map来避免不得不一次又一次地浏览数组,这会导致效率低的 O(n²)时间复杂度。这是 O(n)

function getUniquesOnly(data) {
    return Array.from(
        data.reduce( (acc, o) => acc.set(o.id, acc.has(o.id) ? 0 : o), new Map),
        (([k,v]) => v)
    ).filter( x => x );
}

var data = [
    {
        id: 1,
        title: 'foo'
    },
    {
        id: 2,
        title: 'bar'
    },
    {
        id: 3,
        title: 'bat'
    },
    {
        id: 4,
        title: 'bantz'
    },
    {
        id: 2,
        title: 'bar'
    },
    {
        id: 3,
        title: 'bat'
    }
];

console.log(getUniquesOnly(data));

答案 2 :(得分:0)

简单的实现看起来像这样:

  • 创建一个空集(在本例中为数组),以包含您定义的任何指标的唯一值(IE 比较或通过" id"等唯一值进行比较; )
  • 循环遍历值列表
  • 每当您找到未包含在唯一值集中的值时,请添加

这实质上就是你发布的解决方案的工作方式,除了你的数组中的所有值都是 - 在JavaScript的眼中 - 是唯一的。因此,您需要定义自己的比较值的方法。

.reduce方法可以这样使用:

function areEqual(a, b) { /* define how you want the objects compared here */ }

function contains(a, lst) {
    return lst.reduce(function (acc, x) {
        return acc || areEqual(a, x);
    }, false);
}

function getUnique(lst) {
    return lst.reduce(function (acc, x) {
        if(!contains(x, acc))
        {
            acc.push(x);
        }

        return acc;
    }, []);
}

您可能希望了解JavaScript对象比较的工作原理。为了深入比较(听起来你想要的),我会看existing answers