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

当我需要一个复合键来区分javascript对象时,如何创建一个不同的javascript对象列表?,javascript,arrays,javascript-objects,distinct-values,Javascript,Arrays,Javascript Objects,Distinct Values,是的,有几篇关于用几种语言创建不同列表的文章,但我没有看到任何关于使用复合键或复合键的文章 我有一个包含重复项的对象(联系人)数组,我需要创建一个包含不同值的数组,其中键是email、name和phone字段的组合。对象如下所示: { name: "Name", email: "email@example.com", phone: "5551212", organization: "BigCompany", title: "CEO" } const di

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

我有一个包含重复项的对象(联系人)数组,我需要创建一个包含不同值的数组,其中键是email、name和phone字段的组合。对象如下所示:

{
    name: "Name",
    email: "email@example.com",
    phone: "5551212",
    organization: "BigCompany",
    title: "CEO"
}
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);
    }
}
我可以使用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);
    }
}

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

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

{
    name: "Name",
    email: "email@example.com",
    phone: "5551212",
    organization: "BigCompany",
    title: "CEO"
}
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
(|)需要遵循ES2015的属性顺序(许多操作不是这样),因此您知道,如果每次都以相同的方式创建对象,并且所有可枚举属性都是“自己的”属性,那么对于具有相同
名称的对象,生成的JSON字符串将是相同的,
电子邮件
电话
属性值(如果不同,则不同)。(重要的是“每次都以相同的方式创建对象”,对象
{a:1,b:2}
{b:2,a:1}
会产生不同的JSON字符串。)


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

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()]
注意:如果姓名、电子邮件或电话号码可能包含该子字符串,则使用分隔符
可能被视为不安全。无论使用哪种分隔符,都应确保尽可能不允许在这些字段中输入分隔符,和/或使其在输入中出现的可能性极低:

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)

你可以将钥匙与电子邮件和电话结合起来,但这是为了什么?如果用户更改了电话号码,则密钥会更改,这违反了密钥的概念。这使得假设属性不包含
,一般来说,这不是一个安全的假设。这就是为什么我使用JSON.Fair-ough@T.J.Crowder,但是可以使用任何分隔符,
不太可能是任何姓名、电子邮件或电话号码的一部分。我会澄清我的答案。@T.J.Crowder,我认为您的JSON密钥是一个很好的解决方案。