Szybki sposób na uzyskanie wartości min / max pomiędzy właściwościami obiektu

95

Mam taki obiekt w javascript:

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

Czy istnieje szybki sposób na uzyskanie minimalnej i maksymalnej wartości między właściwościami bez konieczności przeglądania ich wszystkich w pętli? ponieważ obiekt, który mam, jest ogromny i muszę uzyskiwać wartość min / max co dwie sekundy. (Wartości obiektu ciągle się zmieniają).

Youssef
źródło
3
@Oleg: Cóż, biorąc pod uwagę tylko to, może to być JSON. Youssef: Analizuj JSON w obiekcie i iteruj po jego właściwościach.
Felix Kling
@ OlegV.Volkov Używam JSON.parse (), czy to nie powinno sprawić, że będzie to Json?
Youssef,
@Youssef To było JSON (czyli wartość typu String) przed analizą. Jest to wartość Object po przeanalizowaniu.
Šime Vidas
2
JSON jest ciągową notacją obiektów. Kiedy parsujesz JSON do obiektu, nie jest on już w formacie JSON
altschuler,
1
Pozwoliłem sobie na poprawienie obiektu JSON -> w twoim pytaniu, ponieważ komentarze potwierdzają, że o to ci chodziło.
Oleg V. Volkov

Odpowiedzi:

19

W ogólnym przypadku nie ma sposobu, aby znaleźć maksimum / minimum bez przechodzenia przez wszystkie n elementów (jeśli przejdziesz od, 1 do n-1, skąd wiesz, czy element n nie jest większy (lub mniejszy) niż prąd max / min)?

Wspomniał Pan, że wartości zmieniają się co kilka sekund. Jeśli wiesz dokładnie, które wartości się zmieniają, możesz zacząć od poprzednich wartości maksymalnych / minimalnych i porównywać tylko z nowymi, ale nawet w tym przypadku, jeśli jedną z modyfikowanych wartości była Twoja stara wartość maksymalna / minimalna, możesz trzeba je ponownie przejrzeć.

Inną alternatywą - znowu, tylko jeśli liczba zmienianych wartości jest mała - byłoby przechowywanie wartości w strukturze, takiej jak drzewo lub sterta, a gdy nowe wartości nadejdą, należy je odpowiednio wstawić (lub zaktualizować). Ale czy możesz to zrobić, nie jest jasne na podstawie twojego pytania.

Jeśli chcesz uzyskać maksymalny / minimalny element danej listy podczas przeglądania wszystkich elementów, możesz użyć czegoś takiego jak poniższy fragment, ale nie będziesz w stanie tego zrobić bez przejrzenia ich wszystkich

var list = { "a":4, "b":0.5 , "c":0.35, "d":5 };
var keys = Object.keys(list);
var min = list[keys[0]]; // ignoring case of empty list for conciseness
var max = list[keys[0]];
var i;

for (i = 1; i < keys.length; i++) {
    var value = list[keys[i]];
    if (value < min) min = value;
    if (value > max) max = value;
}
carlosfigueira
źródło
2
To nie opisuje, jak uzyskać minimalne / maksymalne wartości właściwości obiektu.
FistOfFury
Iterujesz po obiekcie, a nie liście. mini maxsą niezdefiniowane. Czy for inzamiast tego chciałeś użyć pętli?
tonix
1
Dzięki @tonix, naprawiłem to.
carlosfigueira
143

Aktualizacja: wersja nowoczesna (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}` );


Oryginalna odpowiedź:

Spróbuj tego:

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

i wtedy:

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

Demo na żywo: http://jsfiddle.net/7GCu7/1/

Šime Vidas
źródło
22
Może teżmax = Object.keys(obj).reduce(function(m, k){ return obj[k] > m ? obj[k] : m }, -Infinity);
levi
4
Może to również zrobić teraz: Math.max(...arr);
cmac
1
@cmac Dodałem wersję ES6.
Šime Vidas
@ ŠimeVidas - co oznaczają 3 kropki w funkcji Math.min i max? Dzięki
AME
12

min i max mimo wszystko muszą przepętać tablicę wejściową - jak inaczej mogliby znaleźć największy lub najmniejszy element?

Więc po prostu szybka for..inpętla będzie działać dobrze.

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
źródło
1
To jest świetne dla IE7 / 8. Cheers @ Niet the Dark Absol
ojhawkins
Niekoniecznie jest prawdą, że min i max przechodzą w pętli przez tablicę, aby uzyskać ich wartości. Bardziej realne jest szybkie posortowanie tablicy i wybranie wartości minimalnej i maksymalnej na podstawie tego wyniku
goonerify
7
@goonerify Najszybszym sortowaniem jest to O(n log n), że jest z natury wolniejsze niż to, O(n)że samo skanowanie raz byłoby ...
Niet the Dark Absol
11

Możesz spróbować:

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
źródło
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
źródło
1
Dodano wyjaśnienie.
Andrey Kudriavtsev
4

Możesz także spróbować 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
źródło
3

Korzystając z biblioteki lodash możesz pisać krócej

_({ "a":4, "b":0.5 , "c":0.35, "d":5 }).values().max();
Sergey Zhigalov
źródło
3

Oto rozwiązanie, które pozwala również zwrócić klucz i wykonuje tylko jedną pętlę. Sortuje wpisy Obiektu (według wartości), a następnie zwraca pierwszy i ostatni.

Dodatkowo zwraca posortowany obiekt, który może zastąpić istniejący obiekt, dzięki czemu przyszłe sortowanie będzie szybsze, ponieważ będzie już częściowo posortowane = lepiej niż O (n). Należy zauważyć, że obiekty zachowują swoją kolejność w 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
źródło
Dzięki! Próbowałem wymyślić, jak uzyskać maksimum, jednocześnie zachowując klucz, aby iść z wartością. To pomogło! :)
010011100101
2

W przypadku struktur zagnieżdżonych o różnej głębokości {node: {leaf: 4}, leaf: 1}to zadziała (używając lodash lub podkreślenia):

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
źródło
2
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
źródło
3
Odpowiadając na stare pytanie, twoja odpowiedź byłaby znacznie bardziej przydatna dla innych użytkowników StackOverflow, gdybyś dołączył jakiś kontekst wyjaśniający, w jaki sposób twoja odpowiedź pomaga, szczególnie w przypadku pytania, na które już została zaakceptowana odpowiedź. Zobacz: Jak napisać dobrą odpowiedź .
David Buck
0

To działa dla mnie:

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
źródło
0
// Sorted
let Sorted = Object.entries({ "a":4, "b":0.5 , "c":0.35, "d":5 }).sort((prev, next) => prev[1] - next[1])
>> [ [ 'c', 0.35 ], [ 'b', 0.5 ], [ 'a', 4 ], [ 'd', 5 ] ]


//Min:
Sorted.shift()
>> [ 'c', 0.35 ]

// Max:
Sorted.pop()
>> [ 'd', 5 ]
Timothy Bushell
źródło