Encontrar el valor máximo de un atributo en una matriz de objetos


413

Estoy buscando una forma realmente rápida, limpia y eficiente de obtener el valor máximo "y" en el siguiente segmento JSON:

[
  {
    "x": "8/11/2009",
    "y": 0.026572007
  },
  {
    "x": "8/12/2009",
    "y": 0.025057454
  },
  {
    "x": "8/13/2009",
    "y": 0.024530916
  },
  {
    "x": "8/14/2009",
    "y": 0.031004457
  }
]

¿Es un bucle for la única forma de hacerlo? Estoy interesado en usar de alguna manera Math.max.


44
¿Cómo devolvería el objeto y no solo el valor de atributo min encontrado?
Mike Lyons

1
Para mi propio beneficio, realicé algunas pruebas rápidas de rendimiento en esto. jsperf.com/finding-the-max-value-an-array-of-objects
Andy Polhill

Respuestas:


741

Para encontrar el yvalor máximo de los objetos en array:

Math.max.apply(Math, array.map(function(o) { return o.y; }))

48
¿Podría ampliar esta respuesta para mostrar cómo devolver el objeto en el que se encontró el valor máximo? Eso sería muy útil, gracias!
Mike Lyons

19
¡Aquí está el violín! Espero que esto ayude a alguien jsfiddle.net/45c5r246
mili

24
@MikeLyons si todavía te importa obtener el objeto real: jsfiddle.net/45c5r246/34
tobyodavies

11
¡Por favor expanda su respuesta!
John William Domingo

12
FWIW, entiendo que cuando llamas a apply en una función, ejecuta la función con un valor especificado thisy una serie de argumentos especificados como una matriz. El truco es que aplicar convierte la matriz en una serie de argumentos de funciones reales. Entonces, en este caso, finalmente llama Math.max(0.0265, 0.0250, 0.024, 0.031)con thisla función ejecutada Math. No puedo ver por qué debería ser Mathfrancamente, no creo que la función requiera una válida this. Ah, y aquí hay una explicación adecuada: stackoverflow.com/questions/21255138/…
Daniel C

263

Encuentre el objeto cuya propiedad "Y" tiene el mayor valor en una matriz de objetos

Una forma sería usar Array reduce ..

const max = data.reduce(function(prev, current) {
    return (prev.y > current.y) ? prev : current
}) //returns object

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce http://caniuse.com/#search=reduce (IE9 y superior)

Si no necesita admitir IE (solo Edge), o puede usar un precompilador como Babel, puede usar la sintaxis más concisa.

const max = data.reduce((prev, current) => (prev.y > current.y) ? prev : current)

77
Esta es una buena respuesta, sin embargo, le gustaría pasar un valor inicial o recibiría un error en caso de que la matriz de datos esté vacía. es decir, para un índice de aumento automático de objetos. const max = data.reduce((prev, current) => (prev.y > current.y) ? prev : current, 1)
juliangonzalez

2
Usted plantea un buen punto, probablemente elegiría nullmás de 1.
Andy Polhill

25
Tenga en cuenta que esto devuelve el objeto que tenía el valor máximo, no el valor máximo del objeto. Esto puede o no ser lo que quieres. En mi caso, era lo que quería. +1
John

1
Buena respuesta complementaria!
Leyendas

Excelente respuesta! Al principio, dudé debido a la reducción, pero tendremos que repetir de todos modos, así que ¿por qué no?
shapiro yaacov

147

limpio y simple ES6 (Babel)

const maxValueOfY = Math.max(...arrayToSearchIn.map(o => o.y), 0);

El segundo parámetro debe garantizar un valor predeterminado si arrayToSearchInestá vacío.


8
también es bueno saber que devuelve -Infinity(un valor verdadero ) para una matriz vacía
icl7126

1
Esto es compatible con la mayoría de los navegadores modernos sin Babel ahora.
Eugene Kulabuhov

20
a medida que regresa -Infinitypara una matriz vacía, puede pasar un valor inicial Math.max(...state.allProjects.map(o => o.id), 1);
juliangonzalez

55
Esta debería ser la respuesta aceptada ahora ... definitivamente el enfoque más conciso.
nickb

1
para manejar mayúsculas y minúsculas cambie 0a arrayToSearchIn[0].y. Comparación de la complejidad del tiempo: stackoverflow.com/a/53654364/860099
Kamil Kiełczewski

43

Comparación de Tree ONELINERS que manejan mayúsculas y minúsculas (entrada en amatriz):

var maxA = a.reduce((a,b)=>a.y>b.y?a:b).y;  // 30 chars time complexity:  O(n)

var maxB = a.sort((a,b)=>b.y-a.y)[0].y;     // 27 chars time complexity:  O(nlogn)

var maxC = Math.max(...a.map(o=>o.y));      // 26 chars time complexity: >O(2n)

ejemplo editable aquí . Ideas de: maxA , maxB y maxC (el efecto secundario de maxB es que la matriz ase cambia porque sortestá en su lugar).

Para matrices más grandes, Math.max...se lanzará una excepción: se excedió el tamaño máximo de la pila de llamadas (Chrome 76.0.3809, Safari 12.1.2, fecha 2019-09-13)


2
Métodos muy inteligentes para realizar la tarea. Niza
TetraDev

Lo sentimos, voté por error y no pude deshacerlo sin editar su pregunta porque pasó demasiado tiempo.
Günter Zöchbauer

Gracias gran análisis.
d337

Gracias por este desglose de las opciones disponibles y las diferencias entre los enfoques.
FistOfFury

Una cosa a destacar es que la opción B hace que sea mucho más fácil obtener todo el objeto con el yvalor máximo al dejarlo .yal final.
FistOfFury

24

Me gustaría explicar la breve respuesta aceptada paso a paso:

var objects = [{ x: 3 }, { x: 1 }, { x: 2 }];

// array.map lets you extract an array of attribute values
var xValues = objects.map(function(o) { return o.x; });
// es6
xValues = Array.from(objects, o => o.x);

// function.apply lets you expand an array argument as individual arguments
// So the following is equivalent to Math.max(3, 1, 2)
// The first argument is "this" but since Math.max doesn't need it, null is fine
var xMax = Math.max.apply(null, xValues);
// es6
xMax = Math.max(...xValues);

// Finally, to find the object that has the maximum x value (note that result is array):
var maxXObjects = objects.filter(function(o) { return o.x === xMax; });

// Altogether
xMax = Math.max.apply(null, objects.map(function(o) { return o.x; }));
var maxXObject = objects.filter(function(o) { return o.x === xMax; })[0];
// es6
xMax = Math.max(...Array.from(objects, o => o.x));
maxXObject = objects.find(o => o.x === xMax);


document.write('<p>objects: ' + JSON.stringify(objects) + '</p>');
document.write('<p>xValues: ' + JSON.stringify(xValues) + '</p>');
document.write('<p>xMax: ' + JSON.stringify(xMax) + '</p>');
document.write('<p>maxXObjects: ' + JSON.stringify(maxXObjects) + '</p>');
document.write('<p>maxXObject: ' + JSON.stringify(maxXObject) + '</p>');

Más información:


¡Gran explicación! Podría ser un poco más fácil de leer si no estuviera en los comentarios de código, pero aún así, gran trabajo
Martin

23

Bueno, primero debe analizar la cadena JSON, para que pueda acceder fácilmente a sus miembros:

var arr = $.parseJSON(str);

Use el mapmétodo para extraer los valores:

arr = $.map(arr, function(o){ return o.y; });

Luego puede usar la matriz en el maxmétodo:

var highest = Math.max.apply(this,arr);

O como una frase:

var highest = Math.max.apply(this,$.map($.parseJSON(str), function(o){ return o.y; }));

15
No está etiquetado conjQuery
Robin van Baalen

1
@RobinvanBaalen: Sí, tienes razón. Sin embargo, está etiquetado con JSON, pero la respuesta aceptada lo ignora, y tobyodavies también lo eliminó del tema de la pregunta ... Tal vez debería agregar jquery a la pregunta ...;)
Guffa

8
No importa mucho si @tobyodavies ignoró el hecho de que estaba etiquetado json: no está usando una biblioteca javascript externa en su respuesta :)
Robin van Baalen

12
var data = [
  { 'name': 'Vins', 'age': 27 },
  { 'name': 'Jan', 'age': 38 },
  { 'name': 'Alex', 'age': 80 },
  { 'name': 'Carl', 'age': 25 },
  { 'name': 'Digi', 'age': 40 }
];
var max = data.reduce(function (prev, current) {
   return (prev.age > current.age) ? prev : current
});
//output = {'name': 'Alex', 'age': 80}

2
¿Cómo difiere esto de la respuesta de @ AndyPolhill?
Lewis

7

si usted (o alguien aquí) es libre de usar lodashla biblioteca de utilidades, tiene una función maxBy que sería muy útil en su caso.

por lo tanto, puede usar como tal:

_.maxBy(jsonSlice, 'y');

6

O un tipo simple! Siendo realistas :)

array.sort((a,b)=>a.y<b.y)[0].y

Buena idea +1 (código más corto), pero hay un pequeño error: cambie a.y<a.ya b.y-a.y. Comparación de la complejidad del tiempo aquí: stackoverflow.com/a/53654364/860099
Kamil Kiełczewski

2
Encontrar el máximo es O (n). Esto es O (nlogn). Escribir código simple es bueno siempre que no se sacrifique la eficiencia.
Martillo salvaje

@Wildhammer: en realidad, la micro-optimización vale la pena cuando tienes evidencia de que estás optimizando un cuello de botella. . En la mayoría de los casos, el código simple es una mejor opción que el código de alta eficiencia.
Kamil Kiełczewski

@ KamilKiełczewski Ambas comparaciones de matrices en ese artículo tienen la misma complejidad de tiempo, la diferencia está en su coeficiente. Por ejemplo, uno toma n unidades de tiempo para encontrar la solución, mientras que el otro es 7n. En la teoría de la complejidad del tiempo, ambos son O (n). De lo que estamos hablando en el problema de encontrar max es la comparación de O (n) con O (n logn). Ahora, si puede garantizar que n no exceda de 10, puede usar su solución; de lo contrario, el algoritmo O (n) siempre es el ganador y el rendimiento (experiencia del usuario) siempre es anterior a la experiencia del desarrollador (¡pregunte a la gente de la industria, se lo dicen!) .
Martillo salvaje

@Wildhammer no: incluso si su matriz tiene n = 10000 elementos, el usuario no verá la diferencia a prueba AQUÍ . La optimización del rendimiento es buena solo para el cuello de botella de la aplicación (por ejemplo, necesita procesar grandes matrices), pero en la mayoría de los casos, un enfoque de rendimiento es un enfoque incorrecto y una pérdida de tiempo (= dinero). Este es un error de enfoque de código bien conocido - lea más: "micro-optimización"
Kamil Kiełczewski


2

Aquí está la solución más corta (One Liner) ES6 :

Math.max(...values.map(o => o.y));

1
var max = 0;                
jQuery.map(arr, function (obj) {
  if (obj.attr > max)
    max = obj.attr;
});


1
Here is very simple way to go:

Your DataSet.

let numberArray = [
  {
    "x": "8/11/2009",
    "y": 0.026572007
  },
  {
    "x": "8/12/2009",
    "y": 0.025057454
  },
  {
    "x": "8/13/2009",
    "y": 0.024530916
  },
  {
    "x": "8/14/2009",
    "y": 0.031004457
  }
]

1. First create Array, containing all the value of Y
let result = numberArray.map((y) => y)
console.log(result) >> [0.026572007,0.025057454,0.024530916,0.031004457]

2. let maxValue = Math.max.apply(null, result)
console.log(maxvalue) >> 0.031004457
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.