2016-08-24 27 views
17

Mam dwie tablice obiektów, które reprezentują adresów e-mail, które mają etykietę i wartość:Merge tablicę obiektów posesją korzystających Lodash

var original = [ 
    { 
    label: 'private', 
    value: '[email protected]' 
    }, 
    { 
    label: 'work', 
    value: '[email protected]' 
    } 
]; 

var update = [ 
    { 
    label: 'private', 
    value: '[email protected]' 
    }, 
    { 
    label: 'school', 
    value: '[email protected]' 
    } 
]; 

Teraz chcę porównać i scalić dwie tablice przez pole label , aby wynik wyglądał następująco:

var result = [ 
    { 
    label: 'private', 
    value: '[email protected]' 
    }, 
    { 
    label: 'work', 
    value: '[email protected]' 
    }, 
    { 
    label: 'school', 
    value: '[email protected]' 
    } 
] 

Jak mogę to zrobić np. używając lodash?

+0

Możliwy duplikat [Jak scalić dwie tablice w JavaScript i przedmioty de Duplikat] (http://stackoverflow.com/questions/1584370/how-to-merge-two-arrays-in-javascript- and-de-duplicate-items) –

Odpowiedz

34

_.unionBy():
Ten sposób jest podobny _.union wyjątkiem, że przyjmuje iteratee która jest wywoływana dla każdego elementu macierzy do wytworzenia każdego kryterium, w którym wyjątkowości jest obliczona. Wartości wyników wybierane są z pierwszej tablicy, w której występuje wartość.

var original = [ 
 
    { label: 'private', value: '[email protected]' }, 
 
    { label: 'work', value: '[email protected]' } 
 
]; 
 

 
var update = [ 
 
    { label: 'private', value: '[email protected]' }, 
 
    { label: 'school', value: '[email protected]' } 
 
]; 
 

 
var result = _.unionBy(update, original, "label"); 
 

 
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.15.0/lodash.min.js"></script>

+1

To jest bardzo czyste – jonathanGB

+0

Bardzo ładne! Działa doskonale, dziękuję!:-) – benjiman

+0

@benjiman Serdecznie zapraszamy :) – Andreas

3

Konwertuj listy na obiekty oznaczone label, scal je przez _.assign i przekonwertuj z powrotem na tablicę. Zachowuje nawet porządek pozycji w większości przeglądarek.

var original = [ 
 
    { 
 
    label: 'private', 
 
    value: '[email protected]' 
 
    }, 
 
    { 
 
    label: 'work', 
 
    value: '[email protected]' 
 
    } 
 
]; 
 

 
var update = [ 
 
    { 
 
    label: 'private', 
 
    value: '[email protected]' 
 
    }, 
 
    { 
 
    label: 'school', 
 
    value: '[email protected]' 
 
    } 
 
]; 
 

 
console.log(
 
    _.map(
 
    _.assign(
 
     _.mapKeys(original, v => v.label), 
 
     _.mapKeys(update, v => v.label) 
 
    ) 
 
) 
 
); 
 

 

 
// or remove more duplicated code using spread 
 

 
console.log(
 
    _.map(
 
    _.assign(
 
     ...[original, update].map(
 
     coll => _.mapKeys(coll, v => v.label) 
 
    ) 
 
    ) 
 
) 
 
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.15.0/lodash.js"></script>

+2

Działa doskonale, ale rozwiązanie wykorzystujące _.unionBy() wydaje się być trochę czystsze. Dzięki :-) – benjiman

+0

Tak, prawie płakałem z radości, kiedy to zobaczyłem. Tak prosty, czuje się jak lodash ma funkcję do wszystkiego :) –

+0

To prawda ;-) Czasami po prostu tracisz przegląd. – benjiman

2

może nieco z opóźnieniem, ale wszystkie rozwiązania, jakie obserwowane nie połączyć obie tablice prawidłowo wykorzystują jedną z matryc w pętli, a nadmiar elementy drugiej tablicy nie dodawaj (zakładając, że jest to wymagane).

Właściwym sposobem jest posortowanie obu tablic i przejście do przodu w obu tablicach, łączenie elementów dopasowania i dodawanie brakujących elementów z obu tablic. Poniżej znajdziesz pełne rozwiązanie. To również bierze O (n + m), który jest najlepszy, jaki możesz uzyskać (bez kosztów obliczeniowych dla samego sortowania). W moim kodzie mam już dane posortowane z bazy danych.

function mergeObjectsBasedOnKey(array1, array2, compareFn, mergeFn, alreadySorted) { 
 
    var array1Index = 0; 
 
    var array2Index = 0; 
 

 
    const merged = []; 
 

 
    if (!alreadySorted) { 
 
    array1.sort(compareFn); 
 
    array2.sort(compareFn); 
 
    } 
 

 
    while (array1Index < array1.length && array2Index < array2.length) { 
 
    var comparedValue = compareFn(array1[array1Index], array2[array2Index]); 
 
    if (comparedValue === 0) { 
 
     merged.push(mergeFn(array1[array1Index], array2[array2Index])); 
 
     array1Index++; 
 
     array2Index++; 
 
    } else if (comparedValue < 0) { 
 
     merged.push(mergeFn(array1[array1Index])); 
 
     array1Index++; 
 
    } else { 
 
     merged.push(mergeFn(array2[array2Index])); 
 
     array2Index++; 
 
    } 
 
    } 
 
    while (array1Index < array1.length) { 
 
    merged.push(mergeFn(array1[array1Index])); 
 
    array1Index++; 
 
    } 
 
    while (array2Index < array2.length) { 
 
    merged.push(mergeFn(array2[array2Index])); 
 
    array2Index++; 
 
    } 
 
    return merged; 
 
} 
 

 

 
const array1 = [{ 
 
    "id": 10, 
 
    isArray1: true 
 
    }, 
 
    { 
 
    "id": 11, 
 
    isArray1: true 
 
    }, 
 
    { 
 
    "id": 12, 
 
    isArray1: true 
 
    }, 
 
]; 
 
const array2 = [{ 
 
    "id": 8, 
 
    isArray2: true 
 
    }, 
 
    { 
 
    "id": 11, 
 
    isArray2: true 
 
    }, 
 
    { 
 
    "id": 15, 
 
    isArray2: true 
 
    }, 
 
]; 
 

 
const result = mergeObjectsBasedOnKey(array1, array2, function(a, b) { 
 
    return a.id - b.id; 
 
}, function(a, b) { 
 
    if (b) { 
 
    return _.merge(a, b); 
 
    } 
 
    return _.merge(a, { 
 
    isArray1: true, 
 
    isArray2: true 
 
    }); 
 
}); 
 

 
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>

A wyniki byłyby:

[ { id: 8, isArray2: true, isArray1: true }, 
    { id: 10, isArray1: true, isArray2: true }, 
    { id: 11, isArray1: true, isArray2: true }, 
    { id: 12, isArray1: true, isArray2: true }, 
    { id: 15, isArray2: true, isArray1: true } ] 
0

Tutaj Utworzyłem inny jsfiddle [https://jsfiddle.net/a0b8f6wg/][1] scalić dwa tablicę obiektów wykorzystujących Lodash.

0

W przypadku korzystania lodash 3.x gdzie _.unionBy() tam nie było, można połączyć _.union() i _.uniq() aby uzyskać ten sam rezultat.

var original = [ 
    { label: 'private', value: '[email protected]' }, 
    { label: 'work', value: '[email protected]' } 
]; 

var update = [ 
    { label: 'private', value: '[email protected]' }, 
    { label: 'school', value: '[email protected]' } 
]; 

var result = _.uniq(_.union(update, original), "label"); 

console.log(result);