当我需要一个复合键来区分它时,如何创建一个不同的 javascript 对象列表?

How can I create a distinct list of javascript objects, when I need a compound key to make it distinct?

是的,有几篇关于用多种语言创建不同列表的帖子,但我没有看到任何关于使用复合键或复合键的帖子。

我有一组重复的对象(联系人),我需要从中创建一个不同值的数组,键是 电子邮件名称的组合和 phone 个字段。对象看起来像这样:

{
    name: "Name",
    email: "email@example.com",
    phone: "5551212",
    organization: "BigCompany",
    title: "CEO"
}

我可以使用 map.has() 创建一个不同的列表,仅基于电子邮件:

const distinct = [];
const map = new Map();
for (const item of contacts) {
    if(!map.has(item.email)){
        map.set(item.email, true); // set any value, but add an entry to the Map
        distinct.push(item);
    }
}

...但是我需要为每个联系人使用不同的数组元素,使用相同的电子邮件,但不同的 phone,或相同的 phone,但不同的电子邮件等。阅读文档map.has(),我没有看到关于关键参数是复杂数据结构(在本例中为多个字段)的任何信息。有没有更好的工具,或者我只是错过了文档的那一部分?

您可以创建一个 JSON 字符串用作键,如下所示:

const distinct = [];
const map = new Map();
for (const item of contacts) {
    const {name, email, phone} = item;
    const key = JSON.stringify({name, email, phone});
    if(!map.has(key){
        map.set(key, true);
        distinct.push(item);
    }
}

因为 JSON.stringify (spec | MDN) 需要遵循 ES2015 的 属性 顺序(许多操作不是),你知道如果你以相同的方式创建对象每次并且所有可枚举属性都是 "own" 属性,对于具有相同 nameemail 和 [=15= 的对象,生成的 JSON 字符串将是相同的] 属性 值(如果不同则不同)。 ("create the objects in the same way every time" 很重要,对象 {a: 1, b: 2}{b: 2, a: 1} 导致 不同的 JSON 字符串。)


旁注:如果您只使用 map.hasmap.set(key, true)Set 可能更有意义:

const distinct = [];
const set = new Set();
for (const item of contacts) {
    const {name, email, phone} = item;
    const key = JSON.stringify({name, email, phone});
    if(!set.has(key){
        set.add(key);
        distinct.push(item);
    }
}

您可以使用 Map 通过创建您自己的复合键来存储您的不同联系人:

const contacts = [
  {
    name: "Name",
    email: "email@example.com",
    phone: "5551212",
    organization: "BigCompany",
    title: "CEO"
  },
  // ...
]

// Store distinct contacts.
const map = new Map()

contacts.forEach((c) => {
  /**
   * Any contact with the same name, email, and phone will
   * be considered a duplicate.
   */
  const key = `${c.name}::${c.email}::${c.phone}`
  map.set(key, c)
})

现在您的地图是项目的容器 { key => contact }

要获取不同联系人的列表,请使用:

const list = Array.from(map.values())

// Use spread syntax to accoplish the same thing.
const list2 = [...map.values()]

注意:如果姓名、电子邮件或 phone 号码可能包含该子字符串,则使用分隔符 :: 可能被认为是不安全的。无论您使用哪个定界符,您都应该确保在可能的情况下禁止在这些字段中输入它,and/or 使其在输入中出现的可能性极小:

const delim = '__:DELIM:__'
const key = `${c.name}${delim}${c.email}${delim}${c.phone}`

即便如此,也不能 100% 保证分隔符不会出现在 name 等字段中,除非您对该字段执行输入验证。

编辑:检查T.J。 Crowder 的 JSON 密钥,使用该方法生成您的密钥可以很好地保证没有子字符串问题:

const key = JSON.stringify({name, email, phone});
map.set(key, c)