2011-03-21 11 views
64

jQuery.unique le permite obtener elementos únicos de una matriz, pero los documentos dicen que la función es principalmente para uso interno y solo opera en elementos DOM. Otra respuesta SO dijo que la función unique() trabajó en números, pero que este caso de uso no es necesariamente a prueba en el futuro porque no está explícitamente establecido en los documentos.jQuery función para obtener todos los elementos únicos de una matriz?

Dado esto, ¿hay una función jQuery "estándar" para acceder solo a los valores únicos, específicamente, primitivos como enteros, en una matriz? (Obviamente, podemos construir un lazo con la función each(), pero somos nuevos en jQuery y nos gustaría saber si hay una función jQuery dedicado para esto.)

+1

*** @ Future_Reader - Antes de consultar otros, vea la respuesta de Rubyrider *** – gibberish

+1

@Future_Readers - Mientras verifica la respuesta de Rubyrider, tenga en cuenta que puede ver resultados inesperados al usarla: no es una solución segura o confiable. – Yuck

Respuesta

106

Usted puede utilizar array.filter para devolver el primer elemento de cada distinta de valor

var a = [ 1, 5, 1, 6, 4, 5, 2, 5, 4, 3, 1, 2, 6, 6, 3, 3, 2, 4 ]; 
 

 
var unique = a.filter(function(itm, i, a) { 
 
    return i == a.indexOf(itm); 
 
}); 
 

 
console.log(unique);

Si apoyo IE8 y a continuación es primaria, no utilice el método no soportado filter.

De lo contrario,

if (!Array.prototype.filter) { 
    Array.prototype.filter = function(fun, scope) { 
     var T = this, A = [], i = 0, itm, L = T.length; 
     if (typeof fun == 'function') { 
      while(i < L) { 
       if (i in T) { 
        itm = T[i]; 
        if (fun.call(scope, itm, i, T)) A[A.length] = itm; 
       } 
       ++i; 
      } 
     } 
     return A; 
    } 
} 
+4

ADVERTENCIA: El código anterior BREAKS en IE8 y abajo, que no tienen soporte nativo para 'Array.filter' o' Array.indexOf'. Consulte mi revisión de esta respuesta para ver el código que no se rompe en los navegadores compatibles con jquery. – Dennis

+0

El soporte se inicia en IE9, para obtener más información, visite https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/filter – Organiccat

+1

o use una de las muchas cuñas EcmaScript 5, como [esta por Kriskowal] (https://github.com/kriskowal/es5-shim) – superjos

6

recorrer la matriz y empujar objetos en una almohadilla, como se encuentra con ellos. Haga una referencia cruzada del hash para cada nuevo elemento.

Tenga en cuenta que esto SÓLO funcionará correctamente para primitivos (cadenas, números, nulos, indefinidos, NaN) y algunos objetos que se serializan a la misma función (funciones, cadenas, fechas, posiblemente matrices, según el contenido). Los hashes en esto colisionarán ya que todos serializan a la misma cosa, p. "[object Object]"

Array.prototype.distinct = function(){ 
    var map = {}, out = []; 

    for(var i=0, l=this.length; i<l; i++){ 
     if(map[this[i]]){ continue; } 

     out.push(this[i]); 
     map[this[i]] = 1; 
    } 

    return out; 
} 

Tampoco hay ninguna razón por la que no pueda usar jQuery.unique. Lo único que no me gusta es que destruye el orden de tu matriz. Aquí está el código exacto para que si les interesa:

Sizzle.uniqueSort = function(results){ 
    if (sortOrder) { 
     hasDuplicate = baseHasDuplicate; 
     results.sort(sortOrder); 

     if (hasDuplicate) { 
      for (var i = 1; i < results.length; i++) { 
       if (results[i] === results[i-1]) { 
        results.splice(i--, 1); 
       } 
      } 
     } 
    } 

    return results; 
}; 
9

me gustaría utilizar underscore.js, que proporciona un método uniq que hace lo que quiere.

+1

Ahora el enlace está roto. Verifique [este enlace] (http://underscorejs.org/#uniq) –

43

Simplemente use este código como la base de un plugin JQuery simple.

$.extend({ 
    distinct : function(anArray) { 
     var result = []; 
     $.each(anArray, function(i,v){ 
      if ($.inArray(v, result) == -1) result.push(v); 
     }); 
     return result; 
    } 
}); 

Uso como tan:

$.distinct([0,1,2,2,3]); 
+0

¡Gran extensión! – Wen

13

Basado en respuesta @ de Kennebec, pero fijo para IE8 y por debajo mediante el uso de envolturas jQuery alrededor de la matriz para proporcionar faltan funciones de matriz filter y indexOf:

Es posible que el contenedor $ .makeArray() no sea absolutamente necesario, pero obtendrás resultados impares si omites este contenedor y JSON.stringifica el resultado de lo contrario.

var a = [1,5,1,6,4,5,2,5,4,3,1,2,6,6,3,3,2,4]; 

// note: jQuery's filter params are opposite of javascript's native implementation :(
var unique = $.makeArray($(a).filter(function(i,itm){ 
    // note: 'index', not 'indexOf' 
    return i == $(a).index(itm); 
})); 

// unique: [1, 5, 6, 4, 2, 3] 
+0

Parece que ya no funciona, cambie el filtro por: return i == $ .inArray (itm, a); – Shadaez

5

Paul irlandés tiene un método "Duck Punching" (véase el ejemplo 2) que modifica el método de jQuery $.unique() para devolver elementos únicos de cualquier tipo:

(function($){ 
    var _old = $.unique; 
    $.unique = function(arr){ 
     // do the default behavior only if we got an array of elements 
     if (!!arr[0].nodeType){ 
      return _old.apply(this,arguments); 
     } else { 
      // reduce the array to contain no dupes via grep/inArray 
      return $.grep(arr,function(v,k){ 
       return $.inArray(v,arr) === k; 
      }); 
     } 
    }; 
})(jQuery); 
1

Se puede utilizar un plugin de jQuery llamado Array Utilities para obtener una variedad de artículos únicos. Se puede hacer así:

var distinctArray = $.distinct([1, 2, 2, 3]) 

distinctArray = [1,2,3]

+0

Esta función de unión también admite un número arbitrario de matrices. Este paquete [jquery-array-utilities] (https://libraries.io/bower/jquery-array-utilities) también se puede instalar usando [bower] (https://bower.io). Me gustaría añadir un descargo de responsabilidad que originalmente hice el complemento :) –

4

esta es la solución de js1568, modificado para trabajar en un genérico matriz de objetos , como:

var genericObject=[ 
     {genProp:'this is a string',randomInt:10,isBoolean:false}, 
     {genProp:'this is another string',randomInt:20,isBoolean:false}, 
     {genProp:'this is a string',randomInt:10,isBoolean:true}, 
     {genProp:'this is another string',randomInt:30,isBoolean:false}, 
     {genProp:'this is a string',randomInt:40,isBoolean:true}, 
     {genProp:'i like strings',randomInt:60,isBoolean:true}, 
     {genProp:'this is a string',randomInt:70,isBoolean:true}, 
     {genProp:'this string is unique',randomInt:50,isBoolean:true}, 
     {genProp:'this is a string',randomInt:50,isBoolean:false}, 
     {genProp:'i like strings',randomInt:70,isBoolean:false} 
    ] 

Acepta un parámetro más llamado propertyName, ¡adivina! :)

$.extend({ 
     distinctObj:function(obj,propertyName) { 
      var result = []; 
      $.each(obj,function(i,v){ 
       var prop=eval("v."+propertyName); 
       if ($.inArray(prop, result) == -1) result.push(prop); 
      }); 
      return result; 
     } 
    }); 

así, si necesita extraer una lista de valores únicos para una propiedad dada, por ejemplo, los valores utilizados para la propiedad randomInt, utilice esto:

$.distinctObj(genericObject,'genProp'); 

que devuelve una matriz como esto:

["this is a string", "this is another string", "i like strings", "this string is unique"] 
+0

Me gustaría saber qué escribí para merecer un -1. – Dariozzo

+1

No he votado negativamente (Acabo de ver esta respuesta), pero sugiero que cambie 'eval (" v. "+ PropertyName)' a 'v [propertyName]'. Cada vez que llamas a 'eval' inicias otro compilador. Para un bucle, esto es bastante caro. – Shaz

1

Si alguien está usando knockoutjs intento:

ko.utils.arrayGetDistinctValues() 

Por cierto, tenga en cuenta todas las utilidades ko.utils.array*.

6
// for numbers 
    a = [1,3,2,4,5,6,7,8, 1,1,4,5,6] 
    $.unique(a) 
    [7, 6, 1, 8, 3, 2, 5, 4] 

    // for string 
    a = ["a", "a", "b"] 
    $.unique(a) 
    ["b", "a"] 

Y para los elementos dom no se necesita un ejemplo aquí supongo porque ya lo sabes!

Aquí está el enlace jsFiddle de ejemplo vivo: http://jsfiddle.net/3BtMc/4/

+6

¡Pero la documentación dice que $ .unique() * solo * funciona en elementos DOM! "Ordena una matriz de elementos DOM, en su lugar, con los duplicados eliminados. Tenga en cuenta que esto solo funciona en matrices de elementos DOM, no en cadenas o números". - http://api.jquery.com/jquery.unique/ – Kat

4
function array_unique(array) { 
    var unique = []; 
    for (var i = 0 ; i < array.length ; ++i) { 
     if (unique.indexOf(array[i]) == -1) 
      unique.push(array[i]); 
    } 
    return unique; 
} 
0

A partir de jQuery 3.0 se puede utilizar $.uniqueSort(ARRAY)

Ejemplo

array = ["1","2","1","2"] 
$.uniqueSort(array) 
=> ["1", "2"] 
solución moderna
+0

En realidad, 'uniqueSort' es lo mismo que' unique' en jquery 2. Está pensado para clasificar objetos y no cadenas. – Mike

1

Llanura JavaScript si no' Necesito soporte de IE (Array.from no es compatible con IE).

Puede usar la combinación de Set y Array.from.

var arr = [1, 1, 11, 2, 4, 2, 5, 3, 1]; 
 
var set = new Set(arr); 
 
arr = Array.from(set); 
 

 
console.log(arr);

El objeto Set le permite almacenar valores únicos de cualquier tipo, ya sean valores primitivos o referencias a objetos.

El método Array.from() crea una nueva instancia de Array a partir de un objeto similar a una matriz o iterable.

Cuestiones relacionadas