javascript - recorrer - js array 2 dimension
Cómo combinar dos matrices en JavaScript y desduplicar elementos (30)
ES6
array1.push(...array2) // => don''t remove duplication
O
[...array1,...array2] // => don''t remove duplication
O
[...new Set([...array1 ,...array2])]; // => remove duplication
Tengo dos matrices de JavaScript:
var array1 = ["Vijendra","Singh"];
var array2 = ["Singh", "Shakya"];
Quiero que la salida sea:
var array3 = ["Vijendra","Singh","Shakya"];
La matriz de salida debe tener palabras repetidas eliminadas.
¿Cómo fusiono dos matrices en JavaScript para obtener solo los elementos únicos de cada matriz en el mismo orden en que se insertaron en las matrices originales?
DeDuplicate single o Merge y DeDuplicate múltiples entradas de matriz. Ejemplo a continuación.
Usando ES6 - Set, para de, desestructuración
Escribí esta función simple que toma múltiples argumentos de matriz. Hace más o menos lo mismo que la solución anterior, solo tiene un caso de uso más práctico. Esta función no concatena valores duplicados en una sola matriz, por lo que puede eliminarlos en una etapa posterior.
DEFINICIÓN DE CORTA FUNCIÓN (solo 9 líneas)
/**
* This function merging only arrays unique values. It does not merges arrays in to array with duplicate values at any stage.
*
* @params ...args Function accept multiple array input (merges them to single array with no duplicates)
* it also can be used to filter duplicates in single array
*/
function arrayDeDuplicate(...args){
let set = new Set(); // init Set object (available as of ES6)
for(let arr of args){ // for of loops through values
arr.map((value) => { // map adds each value to Set object
set.add(value); // set.add method adds only unique values
});
}
return [...set]; // destructuring set object back to array object
// alternativly we culd use: return Array.from(set);
}
EJEMPLO DE USO CODEPEN :
// SCENARIO
let a = [1,2,3,4,5,6];
let b = [4,5,6,7,8,9,10,10,10];
let c = [43,23,1,2,3];
let d = [''a'',''b'',''c'',''d''];
let e = [''b'',''c'',''d'',''e''];
// USEAGE
let uniqueArrayAll = arrayDeDuplicate(a, b, c, d, e);
let uniqueArraySingle = arrayDeDuplicate(b);
// OUTPUT
console.log(uniqueArrayAll); // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 43, 23, "a", "b", "c", "d", "e"]
console.log(uniqueArraySingle); // [4, 5, 6, 7, 8, 9, 10]
Un enfoque funcional con ES2015.
Siguiendo el enfoque funcional, una union
de dos Array
s es solo la composición de concat
y filter
. Para proporcionar un rendimiento óptimo, recurrimos al tipo de datos Set
nativo, que está optimizado para búsquedas de propiedades.
De todos modos, la pregunta clave junto con una función de union
es cómo tratar los duplicados. Las siguientes permutaciones son posibles:
Array A + Array B
[unique] + [unique]
[duplicated] + [unique]
[unique] + [duplicated]
[duplicated] + [duplicated]
Las dos primeras permutaciones son fáciles de manejar con una sola función. Sin embargo, los dos últimos son más complicados, ya que no puede procesarlos mientras confíe en las búsquedas de Set
. Dado que el cambio a una simple búsqueda de propiedades del Object
conllevaría un serio impacto en el rendimiento, la siguiente implementación simplemente ignora la tercera y cuarta permutación. Tendrías que construir una versión separada de union
para apoyarlos.
// small, reusable auxiliary functions
const comp = f => g => x => f(g(x));
const apply = f => a => f(a);
const flip = f => b => a => f(a) (b);
const concat = xs => y => xs.concat(y);
const afrom = apply(Array.from);
const createSet = xs => new Set(xs);
const filter = f => xs => xs.filter(apply(f));
// de-duplication
const dedupe = comp(afrom) (createSet);
// the actual union function
const union = xs => ys => {
const zs = createSet(xs);
return concat(xs) (
filter(x => zs.has(x)
? false
: zs.add(x)
) (ys));
}
// mock data
const xs = [1,2,2,3,4,5];
const ys = [0,1,2,3,3,4,5,6,6];
// here we go
console.log( "unique/unique", union(dedupe(xs)) (ys) );
console.log( "duplicated/unique", union(xs) (ys) );
De aquí en adelante, resulta trivial implementar una función unionn
, que acepta cualquier número de arreglos (inspirados en los comentarios de naomik):
// small, reusable auxiliary functions
const uncurry = f => (a, b) => f(a) (b);
const foldl = f => acc => xs => xs.reduce(uncurry(f), acc);
const apply = f => a => f(a);
const flip = f => b => a => f(a) (b);
const concat = xs => y => xs.concat(y);
const createSet = xs => new Set(xs);
const filter = f => xs => xs.filter(apply(f));
// union and unionn
const union = xs => ys => {
const zs = createSet(xs);
return concat(xs) (
filter(x => zs.has(x)
? false
: zs.add(x)
) (ys));
}
const unionn = (head, ...tail) => foldl(union) (head) (tail);
// mock data
const xs = [1,2,2,3,4,5];
const ys = [0,1,2,3,3,4,5,6,6];
const zs = [0,1,2,3,4,5,6,7,8,9];
// here we go
console.log( unionn(xs, ys, zs) );
Resulta que unionn
es solo foldl
(también conocido como Array.prototype.reduce
), que toma union
como su reductor. Nota: Como la implementación no utiliza un acumulador adicional, generará un error cuando lo aplique sin argumentos.
¿Por qué no usas un objeto? Parece que estás tratando de modelar un conjunto. Esto no conservará el orden, sin embargo.
var set1 = {"Vijendra":true, "Singh":true}
var set2 = {"Singh":true, "Shakya":true}
// Merge second object into first
function merge(set1, set2){
for (var key in set2){
if (set2.hasOwnProperty(key))
set1[key] = set2[key]
}
return set1
}
merge(set1, set2)
// Create set from array
function setify(array){
var result = {}
for (var item in array){
if (array.hasOwnProperty(item))
result[array[item]] = true
}
return result
}
Aquí es una toma ligeramente diferente en el bucle. Con algunas de las optimizaciones en la última versión de Chrome, es el método más rápido para resolver la unión de las dos matrices (Chrome 38.0.2111).
jsperf.com/merge-two-arrays-keeping-only-unique-values
var array1 = ["Vijendra", "Singh"];
var array2 = ["Singh", "Shakya"];
var array3 = [];
var arr = array1.concat(array2),
len = arr.length;
while (len--) {
var itm = arr[len];
if (array3.indexOf(itm) === -1) {
array3.unshift(itm);
}
}
bucle while: ~ 589k ops / s
filtro: ~ 445k ops / s
lodash: 308k ops / s
para bucles: 225k ops / s
Un comentario señaló que una de mis variables de configuración estaba causando que mi ciclo se adelantara al resto, porque no tenía que inicializar una matriz vacía para escribir. Estoy de acuerdo con eso, así que reescribí la prueba para igualar el campo de juego e incluí una opción aún más rápida.
http://jsperf.com/merge-two-arrays-keeping-only-unique-values/21
var whileLoopAlt = function(array1, array2) {
var array3 = [];
var arr = array1.concat(array2);
var len = arr.length;
var assoc = {};
while(len--) {
var itm = arr[len];
if(!assoc[itm]) { // Eliminate the indexOf call
array3.unshift(itm);
assoc[itm] = true;
}
}
return array3;
};
En esta solución alternativa, he combinado una solución de matriz asociativa de una respuesta para eliminar la llamada .indexOf()
en el bucle que estaba ralentizando mucho las cosas con un segundo bucle, e incluí algunas de las otras optimizaciones que otros usuarios han sugerido en Sus respuestas también.
La respuesta principal aquí con el bucle doble en cada valor (i-1) sigue siendo significativamente más lenta. A lodash todavía le está yendo bien, y todavía lo recomendaría a cualquiera que no le importe agregar una biblioteca a su proyecto. Para aquellos que no quieren, mi bucle while sigue siendo una buena respuesta y la respuesta del filtro tiene una gran presencia aquí, superando todas mis pruebas con la última versión de Canary Chrome (44.0.2360) hasta el momento de este escrito.
Echa un vistazo a la respuesta de Mike y la respuesta de Dan Stocker si quieres aumentar la velocidad. Esos son, con mucho, el más rápido de todos los resultados después de analizar casi todas las respuestas viables.
Combine un número ilimitado de matrices o no matrices y manténgalo único:
function flatMerge() {
return Array.prototype.reduce.call(arguments, function (result, current) {
if (!(current instanceof Array)) {
if (result.indexOf(current) === -1) {
result.push(current);
}
} else {
current.forEach(function (value) {
console.log(value);
if (result.indexOf(value) === -1) {
result.push(value);
}
});
}
return result;
}, []);
}
flatMerge([1,2,3], 4, 4, [3, 2, 1, 5], [7, 6, 8, 9], 5, [4], 2, [3, 2, 5]);
// [1, 2, 3, 4, 5, 7, 6, 8, 9]
flatMerge([1,2,3], [3, 2, 1, 5], [7, 6, 8, 9]);
// [1, 2, 3, 5, 7, 6, 8, 9]
flatMerge(1, 3, 5, 7);
// [1, 3, 5, 7]
Con Underscore.js o Lo-Dash puedes hacer:
_.union([1, 2, 3], [101, 2, 1, 10], [2, 1]);
=> [1, 2, 3, 101, 10]
En Dojo 1.6+
var unique = [];
var array1 = ["Vijendra","Singh"];
var array2 = ["Singh", "Shakya"];
var array3 = array1.concat(array2); // Merged both arrays
dojo.forEach(array3, function(item) {
if (dojo.indexOf(unique, item) > -1) return;
unique.push(item);
});
Actualizar
Ver código de trabajo.
Esta es una solución de ECMAScript 6 que utiliza los operadores de propagación y los genéricos de matriz.
Actualmente solo funciona con Firefox y posiblemente con la Vista previa técnica de Internet Explorer.
Pero si usas Babel , puedes tenerlo ahora.
// Input: [ [1, 2, 3], [101, 2, 1, 10], [2, 1] ]
// Output: [1, 2, 3, 101, 10]
function mergeDedupe(arr)
{
return [...new Set([].concat(...arr))];
}
La mejor solucion...
Puedes consultar directamente en la consola del navegador pulsando ...
Sin duplicado
a = [1, 2, 3];
b = [3, 2, 1, "prince"];
a.concat(b.filter(function(el) {
return a.indexOf(el) === -1;
}));
Con duplicado
["prince", "asish", 5].concat(["ravi", 4])
Si lo desea, sin duplicado, puede intentar una mejor solución desde aquí: el Código de Shouting .
[1, 2, 3].concat([3, 2, 1, "prince"].filter(function(el) {
return [1, 2, 3].indexOf(el) === -1;
}));
Probar en la consola del navegador Chrome
f12 > console
Salida:
["prince", "asish", 5, "ravi", 4]
[1, 2, 3, "prince"]
Mi centavo y medio
Array.prototype.concat_n_dedupe = function(other_array) {
return this
.concat(other_array) // add second
.reduce(function(uniques, item) { // dedupe all
if (uniques.indexOf(item) == -1) {
uniques.push(item);
}
return uniques;
}, []);
};
var array1 = ["Vijendra","Singh"];
var array2 = ["Singh", "Shakya"];
var result = array1.concat_n_dedupe(array2);
console.log(result);
Nueva solución (que utiliza Array.prototype.indexOf
y Array.prototype.concat
):
Array.prototype.uniqueMerge = function( a ) {
for ( var nonDuplicates = [], i = 0, l = a.length; i<l; ++i ) {
if ( this.indexOf( a[i] ) === -1 ) {
nonDuplicates.push( a[i] );
}
}
return this.concat( nonDuplicates )
};
Uso:
>>> [''Vijendra'', ''Singh''].uniqueMerge([''Singh'', ''Shakya''])
["Vijendra", "Singh", "Shakya"]
Array.prototype.indexOf (para Internet Explorer):
Array.prototype.indexOf = Array.prototype.indexOf || function(elt)
{
var len = this.length >>> 0;
var from = Number(arguments[1]) || 0;
from = (from < 0) ? Math.ceil(from): Math.floor(from);
if (from < 0)from += len;
for (; from < len; from++)
{
if (from in this && this[from] === elt)return from;
}
return -1;
};
Para simplemente fusionar las matrices (sin eliminar duplicados)
Versión ES5 utiliza Array.concat
:
var array1 = ["Vijendra","Singh"];
var array2 = ["Singh", "Shakya"];
var array3 = array1.concat(array2); // Merges both arrays
// [ ''Vijendra'', ''Singh'', ''Singh'', ''Shakya'' ]
La versión ES6 usa la destructuring
const array1 = ["Vijendra","Singh"];
const array2 = ["Singh", "Shakya"];
const array3 = [...array1, ...array2];
Como no hay una forma ''incorporada'' para eliminar duplicados ( ECMA-262 realidad tiene Array.forEach
que sería ideal para esto), tenemos que hacerlo manualmente:
Array.prototype.unique = function() {
var a = this.concat();
for(var i=0; i<a.length; ++i) {
for(var j=i+1; j<a.length; ++j) {
if(a[i] === a[j])
a.splice(j--, 1);
}
}
return a;
};
Entonces, para usarlo:
var array1 = ["Vijendra","Singh"];
var array2 = ["Singh", "Shakya"];
// Merges both arrays and gets unique items
var array3 = array1.concat(array2).unique();
Esto también preservará el orden de los arreglos (es decir, no es necesario clasificarlos).
Ya que muchas personas están molestas con el aumento de prototipo del Array.prototype
y for in
bucles, aquí hay una forma menos invasiva de usarlo:
function arrayUnique(array) {
var a = array.concat();
for(var i=0; i<a.length; ++i) {
for(var j=i+1; j<a.length; ++j) {
if(a[i] === a[j])
a.splice(j--, 1);
}
}
return a;
}
var array1 = ["Vijendra","Singh"];
var array2 = ["Singh", "Shakya"];
// Merges both arrays and gets unique items
var array3 = arrayUnique(array1.concat(array2));
Para aquellos que tienen la suerte de trabajar con navegadores donde está disponible ES5, puede usar Object.defineProperty
siguiente manera:
Object.defineProperty(Array.prototype, ''unique'', {
enumerable: false,
configurable: false,
writable: false,
value: function() {
var a = this.concat();
for(var i=0; i<a.length; ++i) {
for(var j=i+1; j<a.length; ++j) {
if(a[i] === a[j])
a.splice(j--, 1);
}
}
return a;
}
});
Primero concatene las dos matrices, luego filtre solo los elementos únicos.
var a = [1, 2, 3], b = [101, 2, 1, 10];
var c = a.concat(b);
var d = c.filter(function (item, pos) {return c.indexOf(item) == pos});
// d is [1,2,3,101,10]
http://jsfiddle.net/simo/98622/
Editar
Según lo sugerido por @Dmitry (ver el segundo comentario a continuación), una solución más inteligente en cuanto al rendimiento sería filtrar los elementos únicos en b
antes de concatenar con a
var a = [1, 2, 3], b = [101, 2, 1, 10];
var c = a.concat(b.filter(function (item) {
return a.indexOf(item) < 0;
}));
// d is [1,2,3,101,10]
Puedes hacerlo simplemente con ECMAScript 6,
var array1 = ["Vijendra", "Singh"];
var array2 = ["Singh", "Shakya"];
var array3 = [...new Set([...array1 ,...array2])];
console.log(array3); // ["Vijendra", "Singh", "Shakya"];
- Utilice el operador de propagación para concatenar la matriz.
- Use Set para crear un conjunto distinto de elementos.
- Nuevamente use el operador de propagación para convertir el Conjunto en una matriz.
Puedes lograrlo simplemente usando Underscore.js''s => uniq :
array3 = _.uniq(array1.concat(array2))
console.log(array3)
Se imprimirá ["Vijendra", "Singh", "Shakya"] .
Se puede hacer usando Set.
var array1 = ["Vijendra","Singh"];
var array2 = ["Singh", "Shakya"];
var array3 = array1.concat(array2);
var tempSet = new Set(array3);
array3 = Array.from(tempSet);
//show output
document.body.querySelector("div").innerHTML = JSON.stringify(array3);
<div style="width:100%;height:4rem;line-height:4rem;background-color:steelblue;color:#DDD;text-align:center;font-family:Calibri" >
temp text
</div>
Simplemente manténgase alejado de los bucles anidados (O (n ^ 2)), y .indexOf()
(+ O (n)).
function merge(a, b) {
var hash = {}, i;
for (i=0; i<a.length; i++) {
hash[a[i]]=true;
}
for (i=0; i<b.length; i++) {
hash[b[i]]=true;
}
return Object.keys(hash);
}
Simplificó la respuesta de simo y la convirtió en una buena función.
function mergeUnique(arr1, arr2){
return arr1.concat(arr2.filter(function (item) {
return arr1.indexOf(item) === -1;
}));
}
Solo tirando mis dos centavos.
function mergeStringArrays(a, b){
var hash = {};
var ret = [];
for(var i=0; i < a.length; i++){
var e = a[i];
if (!hash[e]){
hash[e] = true;
ret.push(e);
}
}
for(var i=0; i < b.length; i++){
var e = b[i];
if (!hash[e]){
hash[e] = true;
ret.push(e);
}
}
return ret;
}
Este es un método que utilizo mucho, usa un objeto como una tabla hashlookup para realizar la comprobación de duplicados. Suponiendo que el hash es O (1), entonces esto se ejecuta en O (n) donde n es a.length + b.length. Sinceramente, no tengo idea de cómo el navegador hace el hash, pero funciona bien en muchos miles de puntos de datos.
Suponiendo que las matrices originales no necesiten desduplicación, esto debería ser bastante rápido, conservar el orden original y no modificar las matrices originales ...
function arrayMerge(base, addendum){
var out = [].concat(base);
for(var i=0,len=addendum.length;i<len;i++){
if(base.indexOf(addendum[i])<0){
out.push(addendum[i]);
}
}
return out;
}
uso:
var array1 = ["Vijendra","Singh"];
var array2 = ["Singh", "Shakya"];
var array3 = arrayMerge(array1, array2);
console.log(array3);
//-> [ ''Vijendra'', ''Singh'', ''Shakya'' ]
Usando un Set (ECMAScript 2015), será tan simple como eso:
const array1 = ["Vijendra", "Singh"];
const array2 = ["Singh", "Shakya"];
const array3 = Array.from(new Set(array1.concat(array2)));
fusionar dos matrices y eliminar duplicados en es6
let arr1 = [3, 5, 2, 2, 5, 5];
let arr2 = [2, 1, 66, 5];
let unique = [...new Set([...arr1,...arr2])];
console.log(unique);
// [ 3, 5, 2, 1, 66 ]
Parece que la respuesta aceptada es la más lenta en mis pruebas;
nota que estoy fusionando 2 matrices de objetos por clave
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
</head>
<body>
<button type=''button'' onclick=''doit()''>do it</button>
<script>
function doit(){
var items = [];
var items2 = [];
var itemskeys = {};
for(var i = 0; i < 10000; i++){
items.push({K:i, C:"123"});
itemskeys[i] = i;
}
for(var i = 9000; i < 11000; i++){
items2.push({K:i, C:"123"});
}
console.time(''merge'');
var res = items.slice(0);
//method1();
method0();
//method2();
console.log(res.length);
console.timeEnd(''merge'');
function method0(){
for(var i = 0; i < items2.length; i++){
var isok = 1;
var k = items2[i].K;
if(itemskeys[k] == null){
itemskeys[i] = res.length;
res.push(items2[i]);
}
}
}
function method1(){
for(var i = 0; i < items2.length; i++){
var isok = 1;
var k = items2[i].K;
for(var j = 0; j < items.length; j++){
if(items[j].K == k){
isok = 0;
break;
}
}
if(isok) res.push(items2[i]);
}
}
function method2(){
res = res.concat(items2);
for(var i = 0; i < res.length; ++i) {
for(var j = i+1; j < res.length; ++j) {
if(res[i].K === res[j].K)
res.splice(j--, 1);
}
}
}
}
</script>
</body>
</html>
Por el bien de esto ... aquí hay una solución de una sola línea:
const x = [...new Set([[''C'', ''B''],[''B'', ''A'']].reduce( (a, e) => a.concat(e), []))].sort()
// [''A'', ''B'', ''C'']
No es particularmente legible pero puede ayudar a alguien:
- Aplica una función de reducción con el valor del acumulador inicial establecido en una matriz vacía.
- La función de reducción usa concat para agregar cada sub-matriz a la matriz del acumulador.
- El resultado de esto se pasa como un parámetro de constructor para crear un nuevo
Set
. - El operador de propagación se utiliza para convertir el
Set
a una matriz. - La
sort()
función se aplica a la nueva matriz.
La forma más fácil de hacer esto es usarlo concat()
para combinar los arreglos y luego usarlos filter()
para eliminar los duplicados, o usarlos concat()
y luego colocarlos dentro de una Set()
.
Primera forma:
const firstArray = [1,2, 2];
const secondArray = [3,4];
// now lets merge them
const mergedArray = firstArray.concat(secondArray); // [1,2,2,3,4]
//now use filter to remove dups
const removeDuplicates = mergedArray.filter((elem, index) => mergedArray.indexOf(elem) === index); // [1,2,3, 4]
Segunda forma (pero con implicaciones de rendimiento en la interfaz de usuario):
const firstArray = [1,2, 2];
const secondArray = [3,4];
// now lets merge them
const mergedArray = firstArray.concat(secondArray); // [1,2,2,3,4]
const removeDuplicates = new Set(mergedArray);
//Array.indexOf was introduced in javascript 1.6 (ECMA-262)
//We need to implement it explicitly for other browsers,
if (!Array.prototype.indexOf)
{
Array.prototype.indexOf = function(elt, from)
{
var len = this.length >>> 0;
for (; from < len; from++)
{
if (from in this &&
this[from] === elt)
return from;
}
return -1;
};
}
//now, on to the problem
var array1 = ["Vijendra","Singh"];
var array2 = ["Singh", "Shakya"];
var merged = array1.concat(array2);
var t;
for(i = 0; i < merged.length; i++)
if((t = merged.indexOf(i + 1, merged[i])) != -1)
{
merged.splice(t, 1);
i--;//in case of multiple occurrences
}
La implementación del método indexOf
para otros navegadores está tomada de MDC
Array.prototype.add = function(b){
var a = this.concat(); // clone current object
if(!b.push || !b.length) return a; // if b is not an array, or empty, then return a unchanged
if(!a.length) return b.concat(); // if original is empty, return b
// go through all the elements of b
for(var i = 0; i < b.length; i++){
// if b''s value is not in a, then add it
if(a.indexOf(b[i]) == -1) a.push(b[i]);
}
return a;
}
// Example:
console.log([1,2,3].add([3, 4, 5])); // will output [1, 2, 3, 4, 5]
Array.prototype.merge = function(/* variable number of arrays */){
for(var i = 0; i < arguments.length; i++){
var array = arguments[i];
for(var j = 0; j < array.length; j++){
if(this.indexOf(array[j]) === -1) {
this.push(array[j]);
}
}
}
return this;
};
Una mucho mejor función de combinación de matriz.
array1.concat(array2).filter((value, pos, arr)=>arr.indexOf(value)===pos)
Lo bueno de este es el rendimiento y que, en general, cuando trabaja con matrices, está encadenando métodos como el filtro, el mapa, etc., por lo que puede agregar esa línea y concateará y deduplicará array2 con array1 sin necesidad de una referencia a la siguiente. uno (cuando está encadenando métodos que no tiene), ejemplo:
someSource()
.reduce(...)
.filter(...)
.map(...)
// and now you want to concat array2 and deduplicate:
.concat(array2).filter((value, pos, arr)=>arr.indexOf(value)===pos)
// and keep chaining stuff
.map(...)
.find(...)
// etc
(No me gusta contaminar Array.prototipo y esa sería la única forma de respetar la cadena: definir una nueva función la romperá, así que creo que algo como esto es la única forma de lograrlo)