Maneira rápida de obter os valores mínimo / máximo entre as propriedades do objeto

90

Tenho um objeto em javascript como este:

{ "a":4, "b":0.5 , "c":0.35, "d":5 }

Existe uma maneira rápida de obter o valor mínimo e máximo entre as propriedades sem ter que percorrer todos eles? porque o objeto que tenho é enorme e preciso obter o valor mínimo / máximo a cada dois segundos. (Os valores do objeto continuam mudando).

Youssef
fonte
3
@Oleg: Bem, considerando apenas isso, poderia muito bem ser JSON. Youssef: analise o JSON em um objeto e itere sobre suas propriedades.
Felix Kling
@ OlegV.Volkov Estou usando JSON.parse () não deveria ser Json?
Youssef
@Youssef Era JSON (que é um valor String) antes da análise. É um valor de objeto após a análise.
Šime Vidas
2
JSON é a notação de string de objetos. Quando você analisa JSON para um objeto, ele não está mais no formato JSON
altschuler
1
Tomei a liberdade de corrigir o objeto JSON -> em sua pergunta, pois os comentários confirmam que é isso que você quis dizer.
Oleg V. Volkov

Respostas:

19

Não há como encontrar o máximo / mínimo no caso geral sem percorrer todos os n elementos (se você for de 1 para n-1, como saber se o elemento n não é maior (ou menor) que o máx / min atual)?

Você mencionou que os valores mudam a cada dois segundos. Se você sabe exatamente quais valores mudam, você pode começar com seus valores máx. / Mín. Anteriores e apenas comparar com os novos, mas mesmo neste caso, se um dos valores que foram modificados era o antigo máx. / Mín., Você pode precisa percorrê-los novamente.

Outra alternativa - novamente, apenas se o número de valores que mudam for pequeno - seria armazenar os valores em uma estrutura como uma árvore ou um heap e, conforme os novos valores chegam, você os insere (ou atualiza) apropriadamente. Mas se você pode fazer isso, não fica claro com base em sua pergunta.

Se você deseja obter o elemento máximo / mínimo de uma determinada lista enquanto percorre todos os elementos, então você pode usar algo como o snippet abaixo, mas não será capaz de fazer isso sem passar por todos eles

var list = { "a":4, "b":0.5 , "c":0.35, "d":5 };
var min = list[0]; // ignoring case of empty list for conciseness
var max = list[0];
var i;
for (i = 1; i < list.length; i++) {
    if (list[i] < min) min = list[i];
    if (list[i] > max) max = list[i];
}
carlosfigueira
fonte
2
Isso não descreve como obter os valores mínimo / máximo das propriedades de um objeto.
FistOfFury
133

Atualização: versão moderna (ES6 +)

let obj = { a: 4, b: 0.5 , c: 0.35, d: 5 };

let arr = Object.values(obj);
let min = Math.min(...arr);
let max = Math.max(...arr);

console.log( `Min value: ${min}, max value: ${max}` );


Resposta Original:

Experimente isto:

let obj = { a: 4, b: 0.5 , c: 0.35, d: 5 };
var arr = Object.keys( obj ).map(function ( key ) { return obj[key]; });

e depois:

var min = Math.min.apply( null, arr );
var max = Math.max.apply( null, arr );

Demonstração ao vivo: http://jsfiddle.net/7GCu7/1/

Šime Vidas
fonte
21
Também posso fazermax = Object.keys(obj).reduce(function(m, k){ return obj[k] > m ? obj[k] : m }, -Infinity);
levi de
4
Também posso fazer isso agora: Math.max(...arr);
cmac
1
@cmac Eu adicionei uma versão ES6.
Šime Vidas de
@ ŠimeVidas - o que representam os 3 pontos na função Math.min e max? Obrigado
AME
12

mine maxter que percorrer a matriz de entrada de qualquer maneira - de que outra forma eles encontrariam o maior ou o menor elemento?

Portanto, apenas um for..inloop rápido funcionará bem.

var min = Infinity, max = -Infinity, x;
for( x in input) {
    if( input[x] < min) min = input[x];
    if( input[x] > max) max = input[x];
}
Niet the Dark Absol
fonte
1
Isso é ótimo para o IE7 / 8. Cheers @Niet the Dark Absol
ojhawkins
Não é necessariamente verdade que mínimo e máximo percorrem a matriz para obter seus valores. É mais viável que eles classifiquem rapidamente a matriz e selecionem os valores mínimo e máximo com base nesse resultado
goonerify
7
@goonerify O tipo mais rápido é O(n log n), que é inerentemente mais lento do O(n)que apenas escanear uma vez seria ...
Niet the Dark Absol
11

Você poderia tentar:

const obj = { a: 4, b: 0.5 , c: 0.35, d: 5 };
const max = Math.max.apply(null, Object.values(obj));
console.log(max) // 5
Dave Kalu
fonte
5
// 1. iterate through object values and get them
// 2. sort that array of values ascending or descending and take first, 
//    which is min or max accordingly
let obj = { 'a': 4, 'b': 0.5, 'c': 0.35, 'd': 5 }
let min = Object.values(obj).sort((prev, next) => prev - next)[0] // 0.35
let max = Object.values(obj).sort((prev, next) => next - prev)[0] // 5
Andrey Kudriavtsev
fonte
1
Explicação adicionada.
Andrey Kudriavtsev
4

Você também pode tentar com Object.values

const points = { Neel: 100, Veer: 89, Shubham: 78, Vikash: 67 };

const vals = Object.values(points);
const max = Math.max(...vals);
const min = Math.min(...vals);
console.log(max);
console.log(min);

Neel Rathod
fonte
3

Usando a biblioteca Lodash, você pode escrever de forma mais curta

_({ "a":4, "b":0.5 , "c":0.35, "d":5 }).values().max();
Sergey Zhigalov
fonte
3

Aqui está uma solução que permite que você retorne a chave também e faça apenas um loop. Ele classifica as entradas do objeto (por val) e retorna a primeira e a última.

Além disso, ele retorna o Objeto classificado que pode substituir o Objeto existente para que as classificações futuras sejam mais rápidas porque já estará semi-classificado = melhor que O (n). É importante observar que os Objetos mantêm sua ordem no ES6.

const maxMinVal = (obj) => {
  const sortedEntriesByVal = Object.entries(obj).sort(([, v1], [, v2]) => v1 - v2);

  return {
    min: sortedEntriesByVal[0],
    max: sortedEntriesByVal[sortedEntriesByVal.length - 1],
    sortedObjByVal: sortedEntriesByVal.reduce((r, [k, v]) => ({ ...r, [k]: v }), {}),
  };
};

const obj = {
  a: 4, b: 0.5, c: 0.35, d: 5
};

console.log(maxMinVal(obj));

JBallin
fonte
Obrigado! Eu estava tentando descobrir como obter o máximo e ainda manter a chave para acompanhar o valor. Isso ajudou! :)
010011100101
2

Para estruturas aninhadas de profundidade diferente, ou seja {node: {leaf: 4}, leaf: 1}, isso funcionará (usando lodash ou sublinhado):

function getMaxValue(d){
    if(typeof d === "number") {
        return d;
    } else if(typeof d === "object") {
        return _.max(_.map(_.keys(d), function(key) {
            return getMaxValue(d[key]);
        }));
    } else {
        return false;
    }
}
user4815162342
fonte
1
var newObj = { a: 4, b: 0.5 , c: 0.35, d: 5 };
var maxValue = Math.max(...Object.values(newObj))
var minValue = Math.min(...Object.values(newObj))
user12723650
fonte
3
Ao responder a uma pergunta antiga, sua resposta seria muito mais útil para outros usuários do StackOverflow se você incluísse algum contexto para explicar como sua resposta ajuda, especialmente para uma pergunta que já tem uma resposta aceita. Veja: Como escrevo uma boa resposta .
David Buck
0

Isso funciona para mim:

var object = { a: 4, b: 0.5 , c: 0.35, d: 5 };
// Take all value from the object into list
var valueList = $.map(object,function(v){
     return v;
});
var max = valueList.reduce(function(a, b) { return Math.max(a, b); });
var min = valueList.reduce(function(a, b) { return Math.min(a, b); });
jaydip jadhav
fonte