【问题标题】:Array of literal Objects without duplicates in ES6 using Set使用 Set 在 ES6 中没有重复的文字对象数组
【发布时间】:2016-07-25 20:21:47
【问题描述】:

ES6开始,获取没有重复项的数组的代码变得优雅了:

[...new Set(array)];

就是这样!

但是,这仅在数组具有原始数据类型(字符串、布尔值、数字...)的元素时才删除重复项。

一组对象字面量呢? 使用与上面使用的语法接近的语法,如何在不重复的情况下使其工作?

var array=["aaa","bbb","aaa","cc","aaa","bbb"];
var out=[...new Set(array)];
console.log(out)

//----Literal Object 

array=[{n:"J",last:"B"},{n:"J",last:"B"}];
out=[...new Set(array)];
console.log(out)

上面的代码生成了一个包含 2 个元素的集合,但在这种情况下我希望它只有一个。

我可以使用序列化/反序列化方法来实现这一点:

[...new Set(array.map(
    //-- SERIALIZE:
    (e) => `${e.n}:${e.last}`
))].map(
    //-- DE-SERIALIZE:
    (e) => ({ n: `${e.split(':')[0]}`, last: `${e.split(':')[1]}` })
)

但是,我正在寻找 ES6 内置。

【问题讨论】:

  • Set 也适用于对象。但是,在您的情况下,您有两个不同的对象,即使它们具有相同的属性(和值)。您已经定义了自己的逻辑来比较和过滤此类数组。
  • Set 不支持自定义比较器。因此,如果您不想重新发明轮子,则必须使用 Lodash 的 uniqueBy
  • 是的;别人在说什么。 Set 不是那样工作的。

标签: arrays functional-programming ecmascript-6 unique


【解决方案1】:

在 JavaScript 中,如果两个对象不是同一个引用,即使它们看起来相同,它们也是不同的:

var a = {};
var b = {};
console.log(a === b); // false
b = a;
console.log(a === b); // true

集合的工作方式类似:除非添加到其中的对象指的是同一事物,否则它们将是不同的。

自定义集

让它按你想要的方式工作的一个想法是创建你自己的 Set 风格,即 MySet,为其提供作为 Set 工作所需的所有方法和属性。

然后在其实现中,您将在其内部保留一个 Map,您可以在其中为存储在其中的所有内容提供密钥。然后,您可以确保您认为相同的对象在该映射中获得相同的键,因此只存储一次。

一种低效但直接的方法是使用JSON.stringify(item) 作为键。这有其局限性(例如,添加自引用对象会使 JSON.stringify(item) 放弃),但对于其余部分,它可以完成这项工作。

我们可以让MySet 接受一个额外的参数:调用该函数以获取项目的键值。鉴于上述想法,我们将给它默认值JSON.stringify

考虑一下这个实现,添加你的测试代码:

// Implementation of special Set:
class MySet {
    constructor(values = [], keyFunc = JSON.stringify) {
        // Use a map to store the values 
        this._map = new Map();
        // Which function to use for generating an item's key
        this._keyFunc = keyFunc;
        // Add the initial values
        for (var value of [...values]) this.add(value);
    }
    get size() {
        return this._map.size;
    }
    add(item) {
        // Key items by the given function
        this._map.set(this._keyFunc(item), item);
    }
    has(item) {
        return this._map.has(this._keyFunc(item));
    }
    *[Symbol.iterator] () {
        for (var pair of this._map) {
            yield pair[1]; // return the item
        }
    }
    // etc...
}

// Test it:
array = [{n:"J",last:"B"}, {n:"J",last:"B"}];
out = [...new MySet(array)];
console.log(out);

如您所见,虽然集合中添加了两个对象,但它只存储了一个。

【讨论】:

  • 不错的方法,但是添加两个具有不同属性顺序的对象时会失败。
  • 确实,那么这两个对象就不一样了。这是否是失败,有待解释;-)
猜你喜欢
  • 1970-01-01
  • 2018-07-05
  • 2021-12-21
  • 2018-09-24
  • 2019-05-01
  • 2018-08-15
  • 2017-03-13
  • 2018-09-15
相关资源
最近更新 更多