2017-07-04 2 views
0

Ich versuche, ein Objekt durch ein Array von Arrays zu filtern, um ein Array von Objekten zurück zu bekommen.Was ist der effizienteste Weg, um ein Objekt mit einem Array von Arrays zu filtern?

So:

let obj = 
 
{ 
 
    "a.1":1, 
 
    "a.2":2, 
 
    "b.1":3, 
 
    "b.2":4, 
 
    "c.1":5, 
 
    "c.2":6 
 
} 
 

 
let array = 
 
[ 
 
    ["a.1","b.1"], 
 
    ["a"], 
 
    ["b","c.1"] 
 
] 
 

 
let expectedResult = 
 
[ 
 
    { 
 
    "a.1":1, 
 
    "b.1":3, 
 
    }, 
 
    { 
 
    "a.1":1, 
 
    "a.2":2, 
 
    }, 
 
    { 
 
    "b.1":3, 
 
    "b.2":4, 
 
    "c.1":5 
 
    }, 
 
] 
 

 
// this is what I came up with 
 
const filterObjectByArray = (obj, arr) => 
 
    Object.keys(obj) 
 
    .filter(ch => { 
 
     for (var index = 0; index < arr.length; index++) 
 
      if (ch.startsWith(arr[index])) 
 
       return true; 
 
    }) 
 
    .reduce((ret, key) =>{ 
 
     ret[key] = obj[key] 
 
     return ret 
 
    },{}) 
 
    
 
let result = array.map(arr => filterObjectByArray(obj, arr)) 
 

 
//kind of deepEqual 
 
console.log(JSON.stringify(expectedResult) == JSON.stringify(result))

Gibt es ein einfacher oder bequemer Weg, das zu tun? Ich muss diese Operation ziemlich oft machen und mein Objekt wird bis zu ein paar hundert Einträge groß sein, daher sehe ich hier einen potentiellen Flaschenhals.

+0

würde ich nehmen vielleicht einen Blick auf Lodash (http://lodash.com/) Dienstprogramme – Stratboy

+3

, das genau ist, wie ich es getan hätte. Wenn Sie zusätzliche Geschwindigkeit ausdrücken müssen, könnte ich testen, ob ich den funktionalen Ansatz in rein prozedurale (d. H. Ohne 'Filter' und' reduce', nur mit Vanille 'für') und Benchmark austrage. Ich schlage aber auch vor, dass Sie * zuerst * benchmarken, um zu sehen, ob das so langsam ist, wie Sie befürchten (wenn es ein paar hundert Einträge sind, sollte es ziemlich schnell sein, es sei denn, Sie möchten es millionenmal pro Sekunde). Du weißt, "verfrühte Optimierung ist die Wurzel allen Übels" und all dies. – Amadan

+0

Nur Vorsicht 'startsWith' -' a.15' beginnt mit 'a.1', was vermutlich nicht das ist, was Sie wollen. '(ch +". "). startsWith (arr [index] +". ")' ist zuverlässiger ('a.15.' beginnt mit' a.', nicht aber mit 'a.1.'). – Amadan

Antwort

0

Ich würde eine Ein-Typ-Zuordnung der "Basis" (der Buchstabe) zu den "echten" Schlüsseln erstellen und sie dann verwenden, um den Brief in die realen Schlüssel zu übersetzen, wenn das Objekt erstellt wird.

const obj = { 
 
    "a.1": 1, 
 
    "a.2": 2, 
 
    "b.1": 3, 
 
    "b.2": 4, 
 
    "c.1": 5, 
 
    "c.2": 6 
 
}; 
 

 
const array = [ 
 
    ["a.1", "b.1"], 
 
    ["a"], 
 
    ["b", "c.1"] 
 
]; 
 

 
const getBaseKey = (key) => key.match(/^[a-z]+/)[0]; // get the base of the key - the letter. If it's only one letter, you can use key[0] 
 

 
/** create a one time map of keys by their base **/ 
 
const oobjKeysMap = Object.keys(obj).reduce((map, key) => { 
 
    const baseKey = getBaseKey(key); 
 
    const curr = map.get(baseKey) || []; 
 
    curr.push(key); 
 
    return map.set(baseKey, curr); 
 
}, new Map()); 
 

 
const result = array.map((sub) => // iterate the array 
 
    [].concat(...sub.map((k) => k in obj ? k : oobjKeysMap.get(getBaseKey(k)))) // create the least of "real" keys 
 
    .reduce((ret, key) => { // create the object 
 
    ret[key] = obj[key]; 
 
    return ret; 
 
    }, {}) 
 
); 
 

 
console.log(result);

Verwandte Themen