Cercando di risolvere la differenza simmetrica usando Javascript

Sto cercando di capire una soluzione per la differenza simmetrica utilizzando javascript che raggiunge i seguenti obiettivi:

  • accetta un numero non specificato di matrici come argomenti
  • conserva l’ordine originale dei numeri negli array
  • non rimuove duplicati di numeri in matrici singole
  • rimuove i duplicati che si verificano tra gli array

Quindi, ad esempio, se l’input è ([1, 1, 2, 6], [2, 3, 5], [2, 3, 4]), la soluzione sarebbe, [1, 1, 6, 5 , 4].

Sto cercando di risolvere questo come una sfida data da una comunità di coding online. Le istruzioni esatte dello stato della sfida,

Crea una funzione che prende due o più matrici e restituisce una matrice della differenza simmetrica degli array forniti.

Il termine matematico differenza simmetrica si riferisce agli elementi in due insiemi che si trovano nel primo o nel secondo insieme, ma non in entrambi.

Sebbene la mia soluzione sottostante trovi i numeri che sono unici per ciascun array, elimina tutti i numeri che si verificano più di una volta e non mantiene l’ordine dei numeri.

La mia domanda è molto vicina a quella richiesta per trovare differenze simmetriche / elementi unici in più array in javascript . Tuttavia, la soluzione non conserva l’ordine originale dei numeri e non conserva i duplicati di numeri univoci che si verificano nei singoli array.

function sym(args){ var arr = []; var result = []; var units; var index = {}; for(var i in arguments){ units = arguments[i]; for(var j = 0; j  Desired answer: [1, 1, 6. 5. 4] 

Ecco una versione che utilizza l’object Set per effettuare una ricerca più rapida. Ecco la logica di base:

  1. Mette ogni array passato come argomento in un object Set separato (per facilitare la ricerca veloce).
  2. Quindi, itera ciascun elemento passato in array e lo confronta con gli altri oggetti Set (quelli non creati dall’array che viene ripetuto).
  3. Se l’object non viene trovato in nessuno degli altri Set, viene aggiunto al risultato.

Quindi, inizia con il primo array [1, 1, 2, 6] . Poiché 1 non è stato trovato in nessuno degli altri array, ciascuno dei primi due valori 1 viene aggiunto al risultato. Quindi 2 si trova nel secondo set in modo che non venga aggiunto al risultato. Quindi 6 non viene trovato in nessuno degli altri due set, quindi viene aggiunto al risultato. Lo stesso processo si ripete per il secondo array [2, 3, 5] dove 2 e 3 si trovano in altri Set, ma 5 non è così 5 viene aggiunto al risultato. E, per l’ultimo array, solo 4 non è stato trovato negli altri Set. Quindi, il risultato finale è [1,1,6,5,4] .

Gli oggetti Set vengono utilizzati per comodità e prestazioni. Si potrebbe usare .indexOf() per cercarli in ogni array o uno potrebbe creare la propria ricerca Set-like con un object semplice se non si desidera fare affidamento sull’object Set. C’è anche un polyfill parziale per l’object Set che funzionerebbe qui in questa risposta .

 function symDiff() { var sets = [], result = []; // make copy of arguments into an array var args = Array.prototype.slice.call(arguments, 0); // put each array into a set for easy lookup args.forEach(function(arr) { sets.push(new Set(arr)); }); // now see which elements in each array are unique // eg not contained in the other sets args.forEach(function(array, arrayIndex) { // iterate each item in the array array.forEach(function(item) { var found = false; // iterate each set (use a plain for loop so it's easier to break) for (var setIndex = 0; setIndex < sets.length; setIndex++) { // skip the set from our own array if (setIndex !== arrayIndex) { if (sets[setIndex].has(item)) { // if the set has this item found = true; break; } } } if (!found) { result.push(item); } }); }); return result; } var r = symDiff([1, 1, 2, 6], [2, 3, 5], [2, 3, 4]); log(r); function log(x) { var d = document.createElement("div"); d.textContent = JSON.stringify(x); document.body.appendChild(d); } 

Come per tutti i problemi, è meglio iniziare a scrivere un algoritmo:

Versioni concatenate degli array, in cui ogni array viene filtrato per contenere quegli elementi che nessun array diverso da quello corrente contiene

Quindi scrivilo in JS:

 function sym() { var arrays = [].slice.apply(arguments); return [].concat.apply([], // concatenate arrays.map( // versions of the arrays function(array, i) { // where each array return array.filter( // is filtered to contain function(elt) { // those elements which return !arrays.some( // no array function(a, j) { // return i !== j // other than the current one && a.indexOf(elt) >= 0 // contains ; } ); } ); } ) ); } 

Versione non commentata, scritta in modo più sintetico utilizzando ES6:

 function sym(...arrays) { return [].concat(arrays . map((array, i) => array . filter(elt => !arrays . some((a, j) => i !== j && a.indexOf(elt) >= 0)))); } 

Mi sono imbattuto in questa domanda nella mia ricerca della stessa sfida di codifica su FCC. Sono stato in grado di risolverlo usando i cicli while e while , ma ho avuto qualche problema risolvendo usando l’ Array.reduce() raccomandato. Dopo aver appreso un sacco di .reduce e altri array, ho pensato di condividere anche le mie soluzioni.

Questo è il primo modo in cui l’ho risolto, senza usare. .reduce .

 function sym() { var arrays = [].slice.call(arguments); function diff(arr1, arr2) { var arr = []; arr1.forEach(function(v) { if ( !~arr2.indexOf(v) && !~arr.indexOf(v) ) { arr.push( v ); } }); arr2.forEach(function(v) { if ( !~arr1.indexOf(v) && !~arr.indexOf(v) ) { arr.push( v ); } }); return arr; } var result = diff(arrays.shift(), arrays.shift()); while (arrays.length > 0) { result = diff(result, arrays.shift()); } return result; } 

Dopo aver appreso e provato varie combinazioni di metodi, ho trovato questo che penso sia piuttosto succinto e leggibile.

 function sym() { var arrays = [].slice.call(arguments); function diff(arr1, arr2) { return arr1.filter(function (v) { return !~arr2.indexOf(v); }); } return arrays.reduce(function (accArr, curArr) { return [].concat( diff(accArr, curArr), diff(curArr, accArr) ) .filter(function (v, i, self) { return self.indexOf(v) === i; }); }); } 

.filter linea .filter che pensavo fosse abbastanza interessante per dedurre un array. L’ho trovato qui , ma l’ho modificato per utilizzare il terzo parametro callback anziché l’array denominato, a causa del concatenamento del metodo.

Questa sfida è stata molto divertente!

Basta usare _.xor o copiare il codice di lodash.

Questo è il codice JS che utilizza le funzioni di ordine superiore

  function sym(args) { var output; output = [].slice.apply(arguments).reduce(function(previous, current) { current.filter(function(value, index, self) { //for unique return self.indexOf(value) === index; }).map(function(element) { //pushing array var loc = previous.indexOf(element); a = [loc !== -1 ? previous.splice(loc, 1) : previous.push(element)]; }); return previous; }, []); document.write(output); return output; } sym([1, 2, 3], [5, 2, 1, 4]); 

Soluzione javascript pura.

 function diff(arr1, arr2) { var arr3= []; for(var i = 0; i < arr1.length; i++ ){ var unique = true; for(var j=0; j < arr2.length; j++){ if(arr1[i] == arr2[j]){ unique = false; break; } } if(unique){ arr3.push(arr1[i]);} } return arr3; } function symDiff(arr1, arr2){ return diff(arr1,arr2).concat(diff(arr2,arr1)); } symDiff([1, "calf", 3, "piglet"], [7, "filly"]) //[1, "calf", 3, "piglet", 7, "filly"] 

La mia soluzione breve Alla fine, ho rimosso i duplicati per filtro ().

 function sym() { var args = Array.prototype.slice.call(arguments); var almost = args.reduce(function(a,b){ return b.filter(function(i) {return a.indexOf(i) < 0;}) .concat(a.filter(function(i){return b.indexOf(i)<0;})); }); return almost.filter(function(el, pos){return almost.indexOf(el) == pos;}); } sym([1, 1, 2, 5], [2, 2, 3, 5], [3, 4, 5, 5]); //Result: [4,5,1] 

Questo funziona per me:

 function sym() { var args = [].slice.call(arguments); var getSym = function(arr1, arr2) { return arr1.filter(function(each, idx) { return arr2.indexOf(each) === -1 && arr1.indexOf(each, idx + 1) === -1; }).concat(arr2.filter(function(each, idx) { return arr1.indexOf(each) === -1 && arr2.indexOf(each, idx + 1) === -1; })); }; var result = getSym(args[0], args[1]); var len = args.length - 1, i = 2; while (--len) { result = [].concat(getSym(result, args[i])); i++; } return result; } console.info(sym([1, 1, 2, 5], [2, 2, 3, 5], [6, 8], [7, 8], [9])); 

Alternativa: usa la ricerca all’interno di una mappa invece di una matrice

 function sym(...vs){ var has = {}; //flatten values vs.reduce((a,b)=>a.concat(b)). //if element does not exist add it (value==1) //or mark it as multiply found value > 1 forEach(value=>{has[value] = (has[value]||0)+1}); return Object.keys(has).filter(x=>has[x]==1).map(x=>parseInt(x,10)); } console.log(sym([1, 2, 3], [5, 2, 1, 4],[5,7], [5]));//[3,4,7]) 
 function sym(args) { var initialArray = Array.prototype.slice.call(arguments); var combinedTotalArray = initialArray.reduce(symDiff); // Iterate each element in array, find values not present in other array and push values in combinedDualArray if value is not there already // Repeat for the other array (change roles) function symDiff(arrayOne, arrayTwo){ var combinedDualArray = []; arrayOne.forEach(function(el, i){ if(!arrayTwo.includes(el) && !combinedDualArray.includes(el)){ combinedDualArray.push(el); } }); arrayTwo.forEach(function(el, i){ if(!arrayOne.includes(el) && !combinedDualArray.includes(el)){ combinedDualArray.push(el); } }); combinedDualArray.sort(); return combinedDualArray; } return combinedTotalArray; } console.log(sym([1, 1, 2, 5], [2, 2, 3, 5], [3, 4, 5, 5])); 

Crea una mappa con un conteggio di tutti i valori univoci (attraverso gli array). Di concat tutti gli array e filtri valori non univoci utilizzando la mappa.

 const symsym = (...args) => { // create a Map from the unique value of each array const m = args.reduce((r, a) => { // get unique values of array, and add to Map new Set(a).forEach((n) => r.set(n, (r.get(n) || 0) + 1)); return r; }, new Map()); // combine all arrays return [].concat(...args) // remove all items that appear more than once in the map .filter((n) => m.get(n) === 1); }; console.log(symsym([1, 1, 2, 6], [2, 3, 5], [2, 3, 4])); // => Desired answer: [1, 1, 6, 5, 4] 

Un’altra soluzione semplice, ma leggibile:

 /* This filters arr1 and arr2 from elements which are in both arrays and returns concatenated results from filtering. */ function symDiffArray(arr1, arr2) { return arr1.filter(elem => !arr2.includes(elem)) .concat(arr2.filter(elem => !arr1.includes(elem))); } /* Add and use this if you want to filter more than two arrays at a time. */ function symDiffArrays(...arrays) { return arrays.reduce(symDiffArray, []); } console.log(symDiffArray([1, 3], ['Saluton', 3])); // [1, 'Saluton'] console.log(symDiffArrays([1, 3], [2, 3], [2, 8, 5])); // [1, 8, 5] 

Hey se qualcuno è interessato questa è la mia soluzione:

 function sym (...args) { let fileteredArgs = []; let symDiff = []; args.map(arrayEl => fileteredArgs.push(arrayEl.filter((el, key) => arrayEl.indexOf(el) === key ) ) ); fileteredArgs.map(elArr => { elArr.map(el => { let index = symDiff.indexOf(el); if (index === -1) { symDiff.push(el); } else { symDiff.splice(index, 1); } }); }); return (symDiff); } console.log(sym([1, 2, 3, 3], [5, 2, 1, 4])); 
 function sym(arr1, arr2, ...rest) { //creating a array which has unique numbers from both the arrays const union = [...new Set([...arr1,...arr2])]; // finding the Symmetric Difference between those two arrays const diff= union.filter((num)=>!(arr1.includes(num)&&arr2.includes(num))) //if there are more than 2 arrays if(rest.length){ // recurrsively call till rest become 0 // ie diff of 1,2 will be the first parameter so every recurrsive call will reduce // the arrays till diff between all of them are calculated. return sym(diff, rest[0], ...rest.slice(1)) } return diff }