繁体   English   中英

JavaScript 等效于 C# ToDictionary

[英]JavaScript Equivalent of C# ToDictionary

我正在寻找一种方法来获取以下列表:

directory = [
    {
        name: "Albert",
        age: 40,
        gender: "M"
    },
    {
        name: "Suzanne",
        age: 27,
        gender: "F"
    },
    {
        name: "Robert",
        age: 19,
        gender: "M"
    },
    {
        name: "Connie",
        age: 87,
        gender: "F"
    }
]

并在键name上制作字典:

dictionary = {
    "Albert": {
        name: "Albert",
        age: 40,
        gender: "M"
    },
    "Suzanne": {
        name: "Suzanne",
        age: 27,
        gender: "F"
    },
    "Robert": {
        name: "Robert",
        age: 19,
        gender: "M"
    },
    "Connie": {
        name: "Connie",
        age: 87,
        gender: "F"
    }
}

这类似于 C# ToDictionary方法。 我知道我可以在for循环或.each调用中迭代directory ,并在每次迭代中修改dictionary的值。 但是,我更愿意进行类似函数式编程的分配,例如

dictionary = directory.toDictionary(p => p.name);

在 ES6 或 lodash 中是否存在这样的方法?

您可以映射键和值,并使用(即将推出的) Object.fromEntries从这个数组创建一个对象。

 var directory = [{ name: "Albert", age: 40, gender: "M" }, { name: "Suzanne", age: 27, gender: "F" }, { name: "Robert", age: 19, gender: "M" }, { name: "Connie", age: 87, gender: "F" }], result = Object.fromEntries(directory.map(o => [o.name, o])); console.log(result);
 .as-console-wrapper { max-height: 100% !important; top: 0; }

经典方法

 var directory = [{ name: "Albert", age: 40, gender: "M" }, { name: "Suzanne", age: 27, gender: "F" }, { name: "Robert", age: 19, gender: "M" }, { name: "Connie", age: 87, gender: "F" }], result = Object.assign({}, ...directory.map(o => ({ [o.name]: o }))); console.log(result);
 .as-console-wrapper { max-height: 100% !important; top: 0; }

Javascript 的Map非常类似于字典。 它的实例has , get , set , keys , values方法。 它也可以通过forEach方法直接迭代。

您可以使用“键值对”数组构建Map (在引号中,因为实际上我们以某种类似元组的方式使用数组)。

要创建用作字典的Map ,您可以执行以下操作:

 const directory=[{name:"Albert",age:40,gender:"M"},{name:"Suzanne",age:27,gender:"F"},{name:"Robert",age:19,gender:"M"},{name:"Connie",age:87,gender:"F"}]; const myDict = new Map( directory.map(p => [p.name, p]) ); console.log("Has Albert:", myDict.has("Albert")) myDict.forEach(p => { console.log(`${p.name} has age ${p.age}`) });

你可以reduce数组。 使用Object.assign()将每个名称添加为属性

 const directory=[{name:"Albert",age:40,gender:"M"},{name:"Suzanne",age:27,gender:"F"},{name:"Robert",age:19,gender:"M"},{name:"Connie",age:87,gender:"F"}], output = directory.reduce((r, o) => Object.assign(r, { [o.name]: o }), {}) console.log(output)

由于您也询问了lodash解决方案,您可以使用该库的.keyBy()方法。

 const directory = [{name:"Albert",age:40,gender:"M"},{name:"Suzanne",age:27,gender:"F"},{name:"Robert",age:19,gender:"M"},{name:"Connie",age:87,gender:"F"}]; console.log(_.keyBy(directory, o => o.name));
 .as-console {background-color:black !important; color:lime;} .as-console-wrapper {max-height:100% !important; top:0;}
 <script src="https://cdn.jsdelivr.net/npm/lodash@4.17.14/lodash.min.js"></script>

但是,正如我在评论中所说,第一个结构允许多个同名条目,而结果则不允许。 因此,在directory数组包含多个同名对象的情况下,您将只会在结果数据中获得最后一个。

没有特定的内置功能,但使用.reduce()很容易:

let dict = directory.reduce((d, v) => (d[v.name] = v, d), {});

正如对该问题的良好评论所指出的那样,您需要考虑的一件事是重复名称的含义。 这是“坏数据”的情况吗? 这种重复是否应该有一系列名称? 诸如此类的问题特定于数据结构及其在您的特定应用程序中的用途。

下面是我如何添加 ToDictionary 的实现,它允许您也定义一个键选择器,并允许每个键重复值,如果有很多值,这些值将保存到一个数组中。 该方法是我在 Npmjs.com 上托管的库“simpletslinq”的 1.0.14 版的一部分

请注意,我的代码是用 Typescript 编写的,因此您必须在其上运行 tsc typescript 编译器才能创建真正的 Javscript 等效项。 在其核心,我们使用 map 函数来创建字典。 添加的打字稿东西是添加类型检查..

 if (!Array.prototype.ToDictionary) {
  Array.prototype.ToDictionary = function <T>(keySelector: (arg: T) => any): any {
    let hash = {};
    this.map(item => {
      let key = keySelector(item);
      if (!(key in hash)) {
        hash[key] = item;
      }
      else {
        if (!(Array.isArray(hash[key]))) {
          hash[key] = [hash[key]];
        }
        hash[key].push(item);
      }
    });
    return hash;
  }
}

此代码的规范(测试)如下所示:

  it('can apply method ToDictionary on an array, allowing specificaton of a key selector for the dictionary object', () => {
    let heroes = [{ name: "Han Solo", age: 47, gender: "M" }, { name: "Leia", age: 29, gender: "F" }, { name: "Luke", age: 24, gender: "M" }, { name: "Lando", age: 47, gender: "M" }];
    let dictionaryOfHeroes = heroes.ToDictionary<Hero>(x => x.gender);

    let expectedDictionary = {
      "F": {
        name: "Leia", age: 29, gender: "F"
      },
      "M": [
        { name: "Han Solo", age: 47, gender: "M" },
        { name: "Luke", age: 24, gender: "M" },
        { name: "Lando", age: 47, gender: "M" }
      ]
    };
    expect(dictionaryOfHeroes).toEqual(expectedDictionary);
  });
  

NpmRunKit 上的 ToDictionary 规范输出

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM