Быстрый способ получить минимальные / максимальные значения среди свойств объекта

94

У меня есть такой объект в javascript:

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

Есть ли быстрый способ получить минимальное и максимальное значение среди свойств без необходимости перебирать их все? потому что объект, который у меня есть, огромен, и мне нужно получать минимальное / максимальное значение каждые две секунды. (Значения объекта постоянно меняются).

Юсеф
источник
3
@Oleg: Ну, учитывая только это, вполне может быть JSON. Юсеф: Разберите JSON в объект и перебирайте его свойства.
Felix Kling
@ OlegV.Volkov Я использую JSON.parse (), разве это не делает его Json?
Юсеф
@Youssef Это был JSON (строковое значение) до синтаксического анализа. Это значение объекта после анализа.
Шиме Видас
2
JSON - это строковое представление объектов. Когда вы анализируете JSON на объект, он больше не в формате JSON
altschuler
1
Я взял на себя смелость исправить объект JSON -> в вашем вопросе, поскольку комментарии подтверждают, что это именно то, что вы имели в виду.
Олег В. Волков

Ответы:

19

Невозможно найти максимум / минимум в общем случае без перебора всех n элементов (если вы перейдете от 1 к n-1, как узнать, не больше ли (или меньше) элемент n, чем ток макс / мин)?

Вы упомянули, что значения меняются каждые пару секунд. Если вы точно знаете, какие значения меняются, вы можете начать с ваших предыдущих значений max / min и сравнивать только с новыми, но даже в этом случае, если одно из измененных значений было вашим старым max / min, вы можете нужно повторить их снова.

Другой альтернативой - опять же, только если количество изменяющихся значений невелико - было бы хранить значения в такой структуре, как дерево или куча, и по мере поступления новых значений вы должны были бы вставить (или обновить) их соответствующим образом. Но можете ли вы это сделать, неясно, исходя из вашего вопроса.

Если вы хотите получить максимальный / минимальный элемент данного списка, перебирая все элементы, вы можете использовать что-то вроде приведенного ниже фрагмента, но вы не сможете сделать это, не пройдя все из них.

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;
}
Карлосфигейра
источник
2
Это не описывает, как получить минимальные / максимальные значения свойств объекта.
FistOfFury
Вы перебираете объект, а не список. minи maxне определены. Вы хотели for inвместо этого использовать цикл?
tonix
1
Спасибо @tonix, исправил.
Карлосфигейра,
139

Обновление: современная версия (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}` );


Оригинальный ответ:

Попробуй это:

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

а потом:

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

Живая демонстрация: http://jsfiddle.net/7GCu7/1/

Шиме Видас
источник
21
max = Object.keys(obj).reduce(function(m, k){ return obj[k] > m ? obj[k] : m }, -Infinity);
Тоже
4
Также могу сделать это сейчас: Math.max(...arr);
cmac
1
@cmac Я добавил версию ES6.
Шиме Видас
@ ŠimeVidas - что означают 3 точки на функции Math.min & max? Спасибо
AME
2
@AME Читайте здесь: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Шиме Видас,
12

min а также max все равно придется перебирать входной массив - как еще они могли бы найти самый большой или самый маленький элемент?

Так что просто быстрый for..inцикл будет работать нормально.

var min = Infinity, max = -Infinity, x;
for( x in input) {
    if( input[x] < min) min = input[x];
    if( input[x] > max) max = input[x];
}
Ниет Темный Абсол
источник
1
Это отлично подходит для IE7 / 8. Cheers @Niet the Dark Absol
ojhawkins
Необязательно верно, что min и max проходят цикл по массиву, чтобы получить свои значения. Более вероятно, что они
быстро отсортируют
7
@goonerify Самая быстрая сортировка O(n log n), которая по своей сути медленнее, чем при O(n)однократном сканировании ...
Niet the Dark Absol
11

Вы можете попробовать:

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
Дэйв Калу
источник
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
Андрей Кудрявцев
источник
1
Пояснение добавлено.
Андрей Кудрявцев
4

Вы также можете попробовать 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);

Нил Ратод
источник
3

Вот решение, которое также позволяет вернуть ключ и выполняет только один цикл. Он сортирует записи объекта (по значению), а затем возвращает первую и последнюю.

Кроме того, он возвращает отсортированный объект, который может заменить существующий объект, так что будущие сортировки будут быстрее, потому что он уже будет частично отсортирован = лучше, чем O (n). Важно отметить, что объекты сохраняют свой порядок в 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
источник
Благодарность! Я пытался понять, как получить максимум, сохраняя при этом ключ к значению. Это помогло! :)
010011100101
2

Для вложенных структур разной глубины, т.е. {node: {leaf: 4}, leaf: 1}это будет работать (с использованием lodash или подчеркивания):

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;
    }
}
пользователь4815162342
источник
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
источник
3
При ответе на старый вопрос ваш ответ был бы гораздо более полезным для других пользователей StackOverflow, если бы вы включили некоторый контекст, чтобы объяснить, как ваш ответ помогает, особенно для вопроса, на который уже есть принятый ответ. См .: Как написать хороший ответ .
Дэвид Бак,
0

Это работает для меня:

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); });
джайдип джадхав
источник