Nesne dizisini, Nesnenin öznitelik değeriyle dizinlenmiş karma haritaya dönüştürme


305

Kullanım Durumu

Kullanım örneği, bir nesne dizisini, karma eşlemede anahtar olarak ve bir nesnenin kendisi olarak değer olarak değerlendirmek ve kullanmak için sağlanan dizeye veya işleve dayalı bir karma haritaya dönüştürmektir. Bunu kullanmanın yaygın bir örneği, bir nesne dizisini karma nesne eşlemesine dönüştürmektir.

kod

Aşağıda, bir nesne dizisini bir nesnenin öznitelik değeriyle dizinlenmiş bir karma haritaya dönüştüren küçük bir snippet bulunmaktadır. Karma haritanın anahtarını dinamik olarak değerlendirmek için bir işlev sağlayabilirsiniz (çalışma süresi). Umarım bu gelecekte birine yardımcı olur.

function isFunction(func) {
    return Object.prototype.toString.call(func) === '[object Function]';
}

/**
 * This function converts an array to hash map
 * @param {String | function} key describes the key to be evaluated in each object to use as key for hashmap
 * @returns Object
 * @Example 
 *      [{id:123, name:'naveen'}, {id:345, name:"kumar"}].toHashMap("id")
 *      Returns :- Object {123: Object, 345: Object}
 *
 *      [{id:123, name:'naveen'}, {id:345, name:"kumar"}].toHashMap(function(obj){return obj.id+1})
 *      Returns :- Object {124: Object, 346: Object}
 */
Array.prototype.toHashMap = function(key) {
    var _hashMap = {}, getKey = isFunction(key)?key: function(_obj){return _obj[key];};
    this.forEach(function (obj){
        _hashMap[getKey(obj)] = obj;
    });
    return _hashMap;
};

Özeti burada bulabilirsiniz: Nesneler Dizisini HashMap'e dönüştürür .


Nesne yerine JavaScript Haritasını kullanabilirsiniz. Check out stackoverflow.com/a/54246603/5042169
Jun711

Yanıtlar:


471

Bu, aşağıdakilerle oldukça önemsizdir Array.prototype.reduce:

var arr = [
    { key: 'foo', val: 'bar' },
    { key: 'hello', val: 'world' }
];

var result = arr.reduce(function(map, obj) {
    map[obj.key] = obj.val;
    return map;
}, {});

console.log(result);
// { foo:'bar', hello:'world' }

Not: Array.prototype.reduce() IE9 + 'dır, bu nedenle eski tarayıcıları desteklemeniz gerekiyorsa çoklu doldurmanız gerekir.


47
result = arr.reduce((map, obj) => (map[obj.key] = obj.val, map), {});ES6 tek hatlı hayranlar için: D
Teodor Sandu

31
@Mtz İçin ES6 tek satırlık fanlar, aşağıda mateuscb tepkisi çok daha küçük ve daha temizdir: result = new Map(arr.map(obj => [obj.key, obj.val]));. En önemlisi, bir haritanın iade edildiğini açıkça ortaya koyuyor.
Ryan Shillington

2
@RyanShillington burada Array.prototype.reducejmar777 tarafından önerilen bir cevap bağlamındayız . Mapgerçekten daha kısa ama farklı bir şey. Orijinal niyetle aynı çizgideydim. Bunun bir forum olmadığını unutmayın, SO Q / A yapısı hakkında daha fazla bilgi edinmek isteyebilirsiniz.
Teodor Sandu

2
@Mtz Yeterince adil.
Ryan Shillington

1
İstenen bu değil, IMHO. Gösterilen dizinin doğru sonucu olacaktır: { "foo": {key: 'foo', val: 'bar'}, "hello": {key: 'hello', val: 'world'} }. Her bir orijinal öğenin bütünüyle saklanması gerektiğini unutmayın . Ya Q'nun verileri kullanılarak: {"345": {id:345, name:"kumar"}, ...}. Düzeltme: Kodu değiştirmap[obj.key] = obj;
ToolmakerSteve

302

ES6 Haritasını ( oldukça iyi desteklenen ) kullanarak şunları deneyebilirsiniz:

var arr = [
    { key: 'foo', val: 'bar' },
    { key: 'hello', val: 'world' }
];

var result = new Map(arr.map(i => [i.key, i.val]));

// When using TypeScript, need to specify type:
// var result = arr.map((i): [string, string] => [i.key, i.val])

// Unfortunately maps don't stringify well.  This is the contents in array form.
console.log("Result is: " + JSON.stringify([...result])); 
// Map {"foo" => "bar", "hello" => "world"}


4
Ayrıca bir şeyden kurtulmak için sadece aksine Mapkullanmanız gerektiğini unutmayın . Ayrıca, herhangi bir nesnenin sadece dize olarak değil, anahtar olarak da kullanılabileceğini unutmayın. result.get(keyName)result[keyName]
Simon_Weaver

5
Başka bir TypeScript sürümü şu şekilde görünecektir: var result = new Map(arr.map(i => [i.key, i.val] as [string, string]));bazılarının anlaşılması daha kolay olabilir. Not as [string, string]türü kademesi eklendi.
AlexV

Chrome v71'de bu kodu çalıştırdığımda hala bir dizi alıyorum:Result is: [["foo","bar"],["hello","world"]]
Jean-François Beauchamp

PS result, OP tarafından talep edildiği gibi bir karma değildir.
Jean-François Beauchamp

1
Başka bir daktilo versiyonu:var result = new Map<string, string>(arr.map(i => [i.key, i.val]));
Aziz Javed

39

İle lodash , bu kullanılarak yapılabilir keyBy :

var arr = [
    { key: 'foo', val: 'bar' },
    { key: 'hello', val: 'world' }
];

var result = _.keyBy(arr, o => o.key);

console.log(result);
// Object {foo: Object, hello: Object}

Bu bir hashmap değil
Pomme De Terre

37

ES6 spread + Object.assign kullanma:

array = [{key: 'a', value: 'b', redundant: 'aaa'}, {key: 'x', value: 'y', redundant: 'zzz'}]

const hash = Object.assign({}, ...array.map(s => ({[s.key]: s.value})));

console.log(hash) // {a: b, x: y}

2
Mükemmel, tam ihtiyacım olan şey;)
Pierre

1
const hash = Object.assign({}, ...(<{}>array.map(s => ({[s.key]: s.value}))));daktilo ile çalışmak için bu değişikliği yapmak zorunda kaldı.
ruwan800

24

Forma operatörünü kullanma:

const result = arr.reduce(
    (accumulator, target) => ({ ...accumulator, [target.key]: target.val }),
    {});

JsFiddle'da kod snippet'inin gösterilmesi .


7
Bu yüzden tam buradayım! forma operatörü sadece yeni anahtarı atama ve akümülatörü iade etmenin normal eski yolunu nasıl gerçekleştirir? her seferinde yeni bir kopya oluşturduğundan, forma kötü performans gösterir !
AMTourky

1
şimdi her yinelemeye yayıldınız. Redüktörde mutasyona uğramak güvenli olmalıdır. `` const sonucu = arr.reduce ((akümülatör, hedef) => {akümülatör [target.key]: target.val; dönüş akümülatörü}, {}); ``
MTJ

17

Array.prototype.reduce () ve yalnızca JavaScript Nesnesi yerine gerçek JavaScript Haritasını kullanabilirsiniz .

let keyValueObjArray = [
  { key: 'key1', val: 'val1' },
  { key: 'key2', val: 'val2' },
  { key: 'key3', val: 'val3' }
];

let keyValueMap = keyValueObjArray.reduce((mapAccumulator, obj) => {
  // either one of the following syntax works
  // mapAccumulator[obj.key] = obj.val;
  mapAccumulator.set(obj.key, obj.val);

  return mapAccumulator;
}, new Map());

console.log(keyValueMap);
console.log(keyValueMap.size);

Harita ve Nesne arasındaki fark nedir?
Daha önce, Harita JavaScript'te uygulanmadan önce, Object benzer yapıları nedeniyle Harita olarak kullanılıyordu.
Kullanım durumunuza bağlı olarak, sipariş anahtarlarına ihtiyacınız varsa, haritanın boyutuna erişmeniz veya haritadan sık sık ekleme ve çıkarma yapmanız gerekiyorsa, bir Harita tercih edilir.

MDN belgesinden alıntı :
Nesneler, anahtarları değerlere ayarlamanıza, bu değerleri almanıza, anahtarları silmenize ve bir anahtarda bir şeyin depolanıp depolanmadığını belirlemenize olanak tanıdığı için Haritalar'a benzer. Bu nedenle (ve yerleşik alternatifler olmadığından), Nesneler tarihsel olarak Haritalar olarak kullanılmıştır; ancak, bazı durumlarda bir Harita kullanmayı tercih edilen önemli farklılıklar vardır:

  • Bir Nesnenin anahtarları Dizeler ve Sembollerdir, oysa işlevler, nesneler ve herhangi bir ilkel dahil bir Harita için herhangi bir değer olabilirler.
  • Haritadaki anahtarlar, nesneye eklenen anahtarlar sıralanmamışken sıralanmıştır. Böylece, yinelendiğinde, bir Map nesnesi anahtarları ekleme sırasına göre döndürür.
  • Bir nesnenin özelliklerinin manuel olarak belirlenmesi gerekirken, haritanın boyutunu size özelliğiyle kolayca alabilirsiniz.
  • Bir Harita yinelenebilir ve bu nedenle doğrudan yinelenebilir, oysa bir Nesne üzerinde yineleme, anahtarlarının bir şekilde elde edilmesini ve bunların üzerinde yinelenmesini gerektirir.
  • Bir Nesnenin bir prototipi vardır, bu nedenle haritada dikkatli değilseniz anahtarlarınızla çarpışabilecek varsayılan anahtarlar vardır. ES5'ten itibaren map = Object.create (null) kullanılarak atlanabilir, ancak bu nadiren yapılır.
  • Bir Harita, anahtar çiftlerinin sık sık eklenmesini ve kaldırılmasını içeren senaryolarda daha iyi performans gösterebilir.

1
Bir ok eksik. Değişim (mapAccumulator, obj) {...}için(mapAccumulator, obj) => {...}
mayid

15

Yeni Object.fromEntries()yöntemi kullanabilirsiniz .

Misal:

const array = [
   {key: 'a', value: 'b', redundant: 'aaa'},
   {key: 'x', value: 'y', redundant: 'zzz'}
]

const hash = Object.fromEntries(
   array.map(e => [e.key, e.value])
)

console.log(hash) // {a: b, x: y}


12

es2015 sürümü:

const myMap = new Map(objArray.map(obj => [ obj.key, obj.val ]));

4

TypeScript'te yaptığım şey bu gibi şeyleri koyduğum küçük bir yardımcı program kütüphanem var

export const arrayToHash = (array: any[], id: string = 'id') => 
         array.reduce((obj, item) =>  (obj[item[id]] = item , obj), {})

kullanımı:

const hash = arrayToHash([{id:1,data:'data'},{id:2,data:'data'}])

veya 'id' dışında bir tanımlayıcı varsa

const hash = arrayToHash([{key:1,data:'data'},{key:2,data:'data'}], 'key')

Bir nesneyi anahtar olarak kullanmak istiyorsanız, daktilo nesneleri anahtar olarak kullanmanıza izin vermediğinden Nesne yerine
Harita'yı

3

Bunu diğer posterlerde açıklandığı gibi yapmanın daha iyi yolları vardır. Ama saf JS ve ol 'moda şekilde yapışmak istiyorsanız o zaman işte burada:

var arr = [
    { key: 'foo', val: 'bar' },
    { key: 'hello', val: 'world' },
    { key: 'hello', val: 'universe' }
];

var map = {};
for (var i = 0; i < arr.length; i++) {
    var key = arr[i].key;
    var value = arr[i].val;

    if (key in map) {
        map[key].push(value);
    } else {
        map[key] = [value];
    }
}

console.log(map);

azaltma yönteminin bu yöntemden daha fazla kullanılması tavsiye edilir. Bu yöntemi kullanmak istiyorum. basit ve her şeyi görmek kolaydır.
Santhosh Yedidi

Bu yaklaşımı seviyorum. Bence bazen en basit kod en iyisidir. İnsanlar günümüzde değişebilirlik nedeniyle kapalı, ancak içerdiği sürece değişebilirlik aslında oldukça harika ve performans.
Luis Aceituno

3

Yeni ES6 Haritasına dönüştürmek istiyorsanız bunu yapın:

var kvArray = [['key1', 'value1'], ['key2', 'value2']];
var myMap = new Map(kvArray);

Neden bu tür bir Harita kullanmalısınız? Bu size bağlı. Bir göz atın bu .


2

Basit Javascript kullanma

var createMapFromList = function(objectList, property) {
    var objMap = {};
    objectList.forEach(function(obj) {
      objMap[obj[property]] = obj;
    });
    return objMap;
  };
// objectList - the array  ;  property - property as the key

3
içinde hiçbir şey döndürmediğiniz için bu örnekte .map (...) anlamsız kullanılmıyor mu? Bu durumda her biri için öneriyorum.
cuddlecheek

2

İle lodash:

const items = [
    { key: 'foo', value: 'bar' },
    { key: 'hello', value: 'world' }
];

const map = _.fromPairs(items.map(item => [item.key, item.value]));

console.log(map); // { foo: 'bar', hello: 'world' }

1

reduceKullanımda küçük bir gelişme :

var arr = [
    { key: 'foo', val: 'bar' },
    { key: 'hello', val: 'world' }
];

var result = arr.reduce((map, obj) => ({
    ...map,
    [obj.key] = obj.val
}), {});

console.log(result);
// { foo: 'bar', hello: 'world' }

Diğer cevaptan daha mı hızlı ?
orad

@orad muhtemelen akümülatörü yayar ve her yinelemede yeni nesne oluşturur.
Luckylooke

1

Deneyin

let toHashMap = (a,f) => a.reduce((a,c)=> (a[f(c)]=c,a),{});


0

Aşağıda, nesnelerin öznitelik değeriyle dizinlenmiş nesne dizisini karma haritaya dönüştürmek için javascript'te oluşturduğum küçük snippet. Karma haritanın anahtarını dinamik olarak değerlendirmek için bir işlev sağlayabilirsiniz (çalışma süresi).

function isFunction(func){
    return Object.prototype.toString.call(func) === '[object Function]';
}

/**
 * This function converts an array to hash map
 * @param {String | function} key describes the key to be evaluated in each object to use as key for hasmap
 * @returns Object
 * @Example 
 *      [{id:123, name:'naveen'}, {id:345, name:"kumar"}].toHashMap("id")
        Returns :- Object {123: Object, 345: Object}

        [{id:123, name:'naveen'}, {id:345, name:"kumar"}].toHashMap(function(obj){return obj.id+1})
        Returns :- Object {124: Object, 346: Object}
 */
Array.prototype.toHashMap = function(key){
    var _hashMap = {}, getKey = isFunction(key)?key: function(_obj){return _obj[key];};
    this.forEach(function (obj){
        _hashMap[getKey(obj)] = obj;
    });
    return _hashMap;
};

Buradaki özü burada bulabilirsiniz: https://gist.github.com/naveen-ithappu/c7cd5026f6002131c1fa


11
Lütfen, lütfen, lütfen uzatmayı önermeyin Array.prototype!
jmar777

Ahh, anlıyorum. Başlangıçta bunun önerilen bir cevap olduğunu düşündüm :)
jmar777
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.