2015-12-21 6 views
15

Ho due letterali oggetto in questo modo:Il modo migliore per ottenere l'intersezione delle chiavi di due oggetti?

var firstObject = 
{ 
    x: 0, 
    y: 1, 
    z: 2, 

    a: 10, 
    b: 20, 
    e: 30 
} 

var secondObject = 
{ 
    x: 0, 
    y: 1, 
    z: 2, 

    a: 10, 
    c: 20, 
    d: 30 
} 

voglio ottenere l'intersezione delle chiavi questi due letterali oggetto hanno in questo modo:

var intersectionKeys = ['x', 'y', 'z', 'a'] 

Io, ovviamente, posso fare un ciclo e vedere se una chiave con lo stesso nome esiste nell'altro oggetto, ma mi chiedo se questo sarebbe un buon caso per alcune programmazioni funzionali e mappa/filtro/ridurre l'utilizzo? Io stesso non ho fatto molta programmazione funzionale, ma ho la sensazione che possa esistere una soluzione pulita e intelligente per questo problema.

+1

Lodash ha [intersezione] (https://lodash.com/docs#intersection) come metodo, se non erano già a conoscenza . – Xotic750

+0

@ Xotic750 Sembra funzionare solo con gli array? Poi di nuovo, ci sono probabilmente molti modi come 'Object.keys' per ottenere le chiavi come una matrice. – Piwwoli

+3

Certo, avrai bisogno delle chiavi di ogni oggetto, proprio come nelle risposte qui sotto, o ['Object.keys'] (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/ Global_Objects/Object/keys) o lodash ha ['_.keys'] (https://lodash.com/docs#keys). '_.intersection (_. keys (firstObject), _.keys (secondObject));' – Xotic750

risposta

19

Una soluzione senza indexOf.

var firstObject = { x: 0, y: 1, z: 2, a: 10, b: 20, e: 30 }, 
 
    secondObject = { x: 0, y: 1, z: 2, a: 10, c: 20, d: 30 }; 
 

 
function intersection(o1, o2) { 
 
    return Object.keys(o1).concat(Object.keys(o2)).sort().reduce(function (r, a, i, aa) { 
 
     if (i && aa[i - 1] === a) { 
 
      r.push(a); 
 
     } 
 
     return r; 
 
    }, []); 
 
} 
 

 
document.write('<pre>' + JSON.stringify(intersection(firstObject, secondObject), 0, 4) + '</pre>');

Secondo tentativo con O (n).

var firstObject = { x: 0, y: 1, z: 2, a: 10, b: 20, e: 30 }, 
 
    secondObject = { x: 0, y: 1, z: 2, a: 10, c: 20, d: 30 }; 
 

 
function intersection(o1, o2) { 
 
    return Object.keys(o1).filter({}.hasOwnProperty.bind(o2)); 
 
} 
 

 
document.write('<pre>' + JSON.stringify(intersection(firstObject, secondObject), 0, 4) + '</pre>');

+0

Ho un'impressione, gli oggetti js sono sempre ordinati per chiave ... –

+1

@AmitKriplani non garantito in ES5 e garantito per essere in ordine di creazione in ES2015 – zerkms

+2

@NinaScholz: questa è una bella risposta. Sarebbe ancora più bello se il 'reduce' fosse puro (non usasse un risultato' libero') PS: OP non si preoccupa dell'uguaglianza dei valori - è solo un'intersezione di nomi di chiavi – zerkms

4

La procedura che vi suggerisco è:

  1. Prendi il array di chiavi utilizzando Object.keys() per uno degli oggetti.
  2. Trova l'intersezione della matrice utilizzando .filter e verifica se il secondo oggetto contiene una chiave corrispondente alla prima matrice.

var firstObject = { 
 
    x: 0, 
 
    y: 1, 
 
    z: 2, 
 

 
    a: 10, 
 
    b: 20, 
 
    e: 30 
 
} 
 

 
var secondObject = { 
 
    x: 0, 
 
    y: 1, 
 
    z: 2, 
 

 
    a: 10, 
 
    c: 20, 
 
    d: 30 
 
} 
 

 
function getIntKeys(obj1, obj2){ 
 

 
    var k1 = Object.keys(obj1); 
 
    return k1.filter(function(x){ 
 
     return obj2[x] !== undefined; 
 
    }); 
 
    
 
} 
 

 
alert(getIntKeys(firstObject, secondObject));

+0

Probabilmente mi stavo chiedendo lo stesso, come se importasse 'k1.filter' o' k2.filter' in ogni caso ? – Piwwoli

+0

@HunanRostomyan Non credo che possa mai essere falso, poiché il primo valore nella funzione di callback del filtro restituisce il valore corrente dell'array che viene filtrato.In questo caso, viene filtrato k1, rendendo ridondante il primo controllo poiché sappiamo che il valore deve esistere mentre viene passato attraverso il callback. –

+1

@Piwwoli Non importa, l'intersezione di (A e B) e (B e A) è lo stesso insieme, quindi puoi iniziare con ciascun membro di A e controllare se è anche in B, * o * iniziare con membro di B e controlla se è anche in A. Quello che sto suggerendo con la mia domanda, è che non è necessario controllare due appartenenze perché l'elemento ('x') è già preso da uno di questi set (@Monica ho appena spiegato la stessa cosa). –

7

Le risposte fornite sono belle e sorprendenti, ma ci potrebbe essere un problema in void s' answer e cioè:. "Che cosa succede se uno dei valori delle proprietà intenzionalmente impostati undefined "

Nina 's answer è buono (davvero fantastico) ma come siamo ai limiti del domani di JavaS cripta Penso che il mio non sarà troppo male:

var a = { x: undefined, y: 1, z: 2, a: 10, b: 20, e: 30 } 
 
var b = { x: 0, y: 1, z: 2, a: 10, c: 20, d: 30 } 
 

 
function intersect(o1, o2){ 
 
    return Object.keys(o1).filter(k => k in o2) 
 
} 
 

 
document.write('<pre>' + JSON.stringify(intersect(a, b)) + '</pre>');

Problemi correlati