Suponiendo que tengo lo siguiente:
var array =
[
{"name":"Joe", "age":17},
{"name":"Bob", "age":17},
{"name":"Carl", "age": 35}
]
¿Cuál es la mejor manera de poder obtener una matriz de todas las edades distintas de modo que obtenga una matriz de resultados de:
[17, 35]
¿Hay alguna forma de estructurar alternativamente los datos o un método mejor de tal manera que no tenga que repetir cada matriz comprobando el valor de "edad" y comparar con otra matriz para su existencia, y agregarlo si no?
Si hubiera alguna manera, podría extraer las distintas edades sin iterar ...
De manera ineficaz actual me gustaría mejorar ... Si eso significa que en lugar de "matriz" ser una matriz de objetos, pero un "mapa" de objetos con alguna clave única (es decir, "1,2,3") sería esta bien tambien Solo estoy buscando la forma más eficiente de rendimiento.
Lo siguiente es cómo lo hago actualmente, pero para mí, la iteración parece ser mala para la eficiencia a pesar de que funciona ...
var distinct = []
for (var i = 0; i < array.length; i++)
if (array[i].age not in distinct)
distinct.push(array[i].age)
fuente
Set
objetomap
ys son derrochadores. Este trabajo solo toma una.reduce()
etapa simple .Respuestas:
Si esto fuera PHP, construiría una matriz con las claves y las tomaría
array_keys
al final, pero JS no tiene ese lujo. En cambio, intente esto:fuente
array_unique
compararía todo el artículo, no solo la edad como se solicita aquí.flags = {}
es mejor queflags = []
age
es un número entero relativamente pequeño (<120 seguramente)Si está utilizando ES6 / ES2015 o posterior, puede hacerlo de esta manera:
Aquí hay un ejemplo de cómo hacerlo.
fuente
TypeError: (intermediate value).slice is not a function
usando ES6
fuente
array.filter((value, index, self) => self.map(x => x.age).indexOf(value.age) == index)
Podría usar un enfoque de diccionario como este. Básicamente, asigna el valor que desea que sea distinto como clave en el "diccionario" (aquí usamos una matriz como un objeto para evitar el modo diccionario). Si la clave no existía, entonces agrega ese valor como distinto.
Aquí hay una demostración funcional:
Esto será O (n) donde n es el número de objetos en la matriz ym es el número de valores únicos. No hay una forma más rápida que O (n) porque debe inspeccionar cada valor al menos una vez.
La versión anterior de esto utilizaba un objeto, y para in. Estos eran de naturaleza menor, y desde entonces se han actualizado anteriormente. Sin embargo, la razón de un aparente avance en el rendimiento entre las dos versiones en el jsperf original se debe a que el tamaño de la muestra de datos es muy pequeño. Por lo tanto, la comparación principal en la versión anterior fue observar la diferencia entre el mapa interno y el uso del filtro versus las búsquedas en modo diccionario.
He actualizado el código anterior, como se señaló, sin embargo, también he actualizado jsperf para mirar a través de 1000 objetos en lugar de 3. 3 pasó por alto muchos de los escollos de rendimiento involucrados ( jsperf obsoleto ).
Actuación
https://jsperf.com/filter-vs-dictionary-more-data Cuando ejecuté este diccionario fue un 96% más rápido.
fuente
if( typeof(unique[array[i].age]) == "undefined"){ distinct.push(array[i].age); unique[array[i].age] = 0; }
Así es como resolvería esto usando el nuevo Set a través de ES6 para Typecript a partir del 25 de agosto de 2017
fuente
Con las funciones de ES6, puede hacer algo como:
fuente
const uniqueObjects = [ ...new Set( array.map( obj => obj.age) ) ].map( age=> { return array.find(obj => obj.age === age) } )
Simplemente mapearía y eliminaría dups:
Editar: Aight! No es la forma más eficiente en términos de rendimiento, sino la IMO más simple y legible. Si realmente le interesa la microoptimización o tiene grandes cantidades de datos, un
for
ciclo regular será más "eficiente".fuente
if
s. obtendrás resultados muy diferentes con tres millones.Ejemplo ES6
fuente
Para aquellos que desean devolver objetos con todas las propiedades únicas por clave
fuente
Ya hay muchas respuestas válidas, pero quería agregar una que use solo el
reduce()
método porque es limpio y simple.Úselo así:
fuente
La
forEach
versión de la respuesta de @ travis-j (útil en los navegadores modernos y el mundo Node JS):34% más rápido en Chrome v29.0.1547: http://jsperf.com/filter-versus-dictionary/3
Y una solución genérica que toma una función de mapeador (un poco más lento que el mapa directo, pero eso es de esperar):
fuente
He empezado a poner a subrayado Underscore en todos los proyectos nuevos de forma predeterminada para no tener que pensar en estos pequeños problemas de mezcla de datos.
Produce
[17, 35]
.fuente
Aquí hay otra forma de resolver esto:
No tengo idea de qué tan rápido se compara esta solución con las otras, pero me gusta el aspecto más limpio. ;-)
EDITAR: Bien, lo anterior parece ser la solución más lenta de todas aquí.
He creado un caso de prueba de rendimiento aquí: http://jsperf.com/distinct-values-from-array
En lugar de probar las edades (enteros), elegí comparar los nombres (cadenas).
El método 1 (solución de TS) es muy rápido. Curiosamente, el Método 7 supera a todas las demás soluciones, aquí me acabo de deshacer de .indexOf () y utilicé una implementación "manual" del mismo, evitando llamadas a funciones en bucle:
La diferencia en el rendimiento con Safari y Firefox es sorprendente, y parece que Chrome hace el mejor trabajo en optimización.
No estoy exactamente seguro de por qué los fragmentos anteriores son tan rápidos en comparación con los demás, tal vez alguien más sabio que yo tenga una respuesta. ;-)
fuente
usando lodash
fuente
Usando Lodash
Devoluciones [17,35]
fuente
fuente
underscore.js
_.uniq(_.pluck(array,"age"))
fuente
Aquí hay una solución versátil que utiliza reduce, permite el mapeo y mantiene el orden de inserción.
elementos : una matriz
asignador : una función unaria que asigna el elemento a los criterios, o vacía para asignar el elemento en sí.
Uso
Puede agregar esto a su prototipo de matriz y omitir el parámetro de elementos si ese es su estilo ...
También puede usar un conjunto en lugar de una matriz para acelerar la coincidencia.
fuente
fuente
Acabo de encontrar esto y pensé que es útil
Nuevamente usando subrayado , así que si tienes un objeto como este
te dará solo los objetos únicos.
Lo que sucede aquí es que
indexBy
devuelve un mapa como estey solo porque es un mapa, todas las claves son únicas.
Entonces solo estoy asignando esta lista de nuevo a la matriz.
En caso de que solo necesite los valores distintos
Tenga en cuenta que
key
se devuelve como una cadena, por lo que si necesita números enteros, debe hacerlofuente
Creo que estás buscando la función groupBy (usando Lodash)
produce resultado:
Demostración de jsFiddle: http://jsfiddle.net/4J2SX/201/
fuente
Si, como yo, prefiere una opción más "funcional" sin comprometer la velocidad, este ejemplo utiliza una búsqueda rápida del diccionario envuelta en el interior para reducir el cierre.
Según esta prueba, mi solución es dos veces más rápida que la respuesta propuesta
fuente
fuente
Sé que mi código tiene poca longitud y poca complejidad de tiempo, pero es comprensible, así que lo intenté de esta manera.
Estoy tratando de desarrollar una función basada en prototipos aquí y el código también cambia.
Aquí, Distinct es mi propia función prototipo.
fuente
Si tiene Array.prototype.includes o está dispuesto a rellenarlo , esto funciona:
fuente
El siguiente código mostrará la matriz única de edades, así como la nueva matriz que no tiene edad duplicada
fuente
Escribí el mío en TypeScript, para un caso genérico, como el de Kotlin
Array.distinctBy {}
...Donde
U
es hashable, por supuesto. Para los objetos, es posible que necesite https://www.npmjs.com/package/es6-json-stable-stringifyfuente
En caso de que necesite un objeto entero único
[Objeto {x: 1, y: 2}, Objeto {x: 2, y: 1}]
fuente
Responder esta vieja pregunta no tiene sentido, pero hay una respuesta simple que habla de la naturaleza de Javascript. Los objetos en Javascript son inherentemente tablas hash. Podemos usar esto para obtener un hash de claves únicas:
Entonces podemos reducir el hash a una matriz de valores únicos:
Eso es todo lo que necesitas. La matriz a2 contiene solo las edades únicas.
fuente
Simple línea con gran rendimiento. 6% más rápido que las soluciones ES6 en mis pruebas .
fuente
array.map( o => o.age).filter( (v,i,a) => a.indexOf(v)===i)
. Utilizo la palabra clave de función tan raramente ahora que tengo que leer las cosas dos veces cuando la veo 😊