簡體   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