2017-05-10 4 views
0

Ich versuche, einige Mapping/Reduzierung auf einige Javascript-Objekt und scheitern kläglich.Karte Reduzieren über Javascript Array von Objekten mit schlechter Leistung

Die Daten, wie sie aus dem Backend kommt kommt in etwas wie folgt aussehen:

[ 
    {table:"a1", data: {colA:1,colB:2,colC:3}}, 
    {table:"a2", data: {colA:2,colB:3,colC:4}}, 
    {table:"a3", data: {colA:3,colB:4,colC:5}} 
] 

Recharts die Daten in folgendem Format benötigt (die Quelldatenschlüssel als eindeutige „name“ Schlüssel für das Ergebnis machen

)
[ 
    {name: 'colA', a1: 1, a2: 2, a3: 3}, 
    {name: 'colB', a1: 2, a2: 3, a3: 4}, 
    {name: 'colC', a1: 3, a2: 4, a3: 5} 
] 

Meine aktuelle Lösung ist derzeit O(n^n), weil ich ein Ergebnisobjekt baue, und Schleifen über es jedes Mal. Ich benutze ECMA6/Babel sowie Lodash. Jede Anleitung würde sehr geschätzt werden! Vielen Dank!

Edit: Hier ist meine aktuelle Lösung

var dest = [] 
Lodash.forEach(source,(o) => { 
    var table = o.table; 
    Lodash.forEach(o.data, (p,q) => { 
    // See if the element is in the array 
    const index = Lodash.findIndex(dest,(a) => {return a.name === q}); 
    if (index === -1) { 
     var obj = {}; 
     obj[table] = Number(p); 
     obj.name = q; 
     dest.push(obj); 
    } else { 
     dest[index][table] = Number(p); 
    } 
    }) 
}); 
+1

Was genau das Problem ist? Wenn Sie Leistung benötigen, verwenden Sie rohe "for". – estus

+3

Können Sie Ihre aktuelle Lösung posten? – James

+0

Bitte zeigen Sie uns Ihren aktuellen Code an. – Bergi

Antwort

1

zu starten, die Geschwindigkeit des Algorithmus ist tatsächlich O (n^n^n), weil Sie drei Schleifen verschachtelt sind. Die Art, wie ich es vereinfachen würde, besteht darin, zuerst ein Objekt zu verwenden und dann ein Array aus dem Objekt zu erstellen. Wie so:

function convert(original) { 
 
    var tmp = {}; 
 
    for(var tableIndex in original) { 
 
     var tableObj = original[tableIndex]; 
 
     for(var colKey in tableObj.data) { 
 
      var col = tableObj.data[colKey]; 
 
      if(tmp[colKey] === undefined) { 
 
       tmp[colKey] = {name: colKey}; 
 
      } 
 
      tmp[colKey][tableObj.table] = col 
 
     } 
 
    } 
 

 
    var output = []; 
 
    for(var index in tmp) { 
 
     output.push(tmp[index]); 
 
    } 
 

 
    return output; 
 
} 
 

 
var original = [ 
 
    {table:"a1", data: {colA:1,colB:2,colC:3}}, 
 
    {table:"a2", data: {colA:2,colB:3,colC:4}}, 
 
    {table:"a3", data: {colA:3,colB:4,colC:5}} 
 
] 
 

 
console.log(convert(original));

Dies wird die Notwendigkeit einer Schleife über die Ergebnismatrix eliminieren auf die Objekte hinzuzufügen. Sie haben immer noch eine O (n^m) + O (l) -Bedingung, wenn Sie über das Eingabearray und seine Daten iterieren, aber Sie haben keine komplexere Geschwindigkeitsbedingung, indem Sie auch bei jeder Iteration über das Ergebnisarray iterieren .

Diese Funktion kann auch Fälle behandeln, in denen Ihre Daten pro Tabelle unterschiedlich sein können. So können Sie beispielsweise colA und colB aber nicht colC in einem der Einträge haben. Oder Sie haben möglicherweise eine Spalte für einen anderen Eintrag.

1

Sie können dies massiv vereinfachen, wenn Sie eine Karte verwenden, um die eventuellen Spalten zu verfolgen. Indem Sie sie in einer Karte speichern, erhalten Sie den Vorteil einer konstanten Nachschlagezeit. Wenn wir sagen, dass die Anzahl der Tabellen N ist und die Anzahl der Spalten M ist, dann erhalten Sie O (N * M).

let input = [ 
 
    { table: "a1", data: { colA: 1, colB: 2, colC: 3 } }, 
 
    { table: "a2", data: { colA: 2, colB: 3, colC: 4 } }, 
 
    { table: "a3", data: { colA: 3, colB: 4, colC: 5 } } 
 
]; 
 

 
let desiredOutput = [ 
 
    { name: 'colA', a1: 1, a2: 2, a3: 3 }, 
 
    { name: 'colB', a1: 2, a2: 3, a3: 4 }, 
 
    { name: 'colC', a1: 3, a2: 4, a3: 5 } 
 
]; 
 

 
let keys = null; 
 
let map = null; 
 

 
input.forEach(row => { 
 
    if (map === null) { 
 
    // Cache the column names 
 
    keys = Object.keys(row.data); 
 
    
 
    // Generates objects such a `{ name: 'colA' }` 
 
    // and stores them at a key of 'colA' 
 
    map = keys 
 
     .reduce((o, k) => (o[k] = { 
 
     name: k 
 
     }, o), {}); 
 
    } 
 

 
    // For each column ('colA', 'colB', etc.) 
 
    keys.forEach(key => { 
 
    // Create a new property for the table name 
 
    // ('a1', 'a2', etc.) 
 
    // and copy the matching column value from the input 
 
    map[key][row.table] = row.data[key]; 
 
    }); 
 
}); 
 

 
// Convert the map to an array of just the values 
 
let output = Object.values(map); 
 
console.log(JSON.stringify(output) === JSON.stringify(desiredOutput)); 
 
console.log(output);

+0

Nette Verwendung von einigen Hilfsmethoden wie reduce und forEach. Seien Sie sich jedoch bewusst, dass sie auch ihren eigenen Overhead produzieren. Ich testete unsere beiden Lösungen und testete bei ~ 1500ms für 1,000,000 Iterationen, wobei meine bei ~ 900ms für die gleiche Anzahl von Iterationen taktet. Der einzige Unterschied zwischen uns besteht darin, dass Sie die Hilfsmethoden verwenden, während ich mehr Vanille-Javascript verwende. Sei vorsichtig mit der Bequemlichkeit. –

+0

@PeterLaBanca Ganz richtig. Wenn der Datensatz sehr groß ist und Geschwindigkeit absolut erforderlich ist, sollten Hilfsmethoden vermieden werden. –

Verwandte Themen