Пошук максимального значення атрибута в масиві об'єктів


413

Я шукаю дійсно швидкий, чистий та ефективний спосіб отримати значення "max" у наступному фрагменті 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
  }
]

Чи єдиний спосіб вирішити це проблематика? Я захоплююсь якось використанням Math.max.


4
Як би ви повернули об'єкт, а не лише знайдене значення min attr?
Майк Ліонс

1
Для власної вигоди я провів кілька швидких тестів на перф. jsperf.com/finding-the-max-value-an-array-of-objects
Енді Полхілл

Відповіді:


739

Щоб знайти максимальне yзначення об'єктів у array:

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

47
Чи можете ви розширити цю відповідь, щоб показати, як повернути об’єкт, у якому було знайдено максимальне значення? Це було б дуже корисно, дякую!
Майк Ліонс

19
Ось скрипка! сподіваюся, що це допоможе комусь jsfiddle.net/45c5r246
мілі

24
@MikeLyons, якщо ви все ще хочете отримати фактичний об’єкт: jsfiddle.net/45c5r246/34
tobyodavies

11
Розкрийте, будь ласка, свою відповідь!
Джон Вільям Домінго

12
FWIW, наскільки я розумію, коли ви викликаєте застосувати функцію, вона виконує функцію із заданим значенням thisта рядом аргументів, вказаних у вигляді масиву. Хитрість полягає в тому, що застосувати перетворює масив у ряд фактичних аргументів функції. Так що в цьому випадку він , нарешті , викликає Math.max(0.0265, 0.0250, 0.024, 0.031)з thisфункцією , виконуваної бути Math. Я не можу зрозуміти, чому це має бути Mathвідверто, я не думаю, що ця функція вимагає дійсної this. О, і ось правильне пояснення: stackoverflow.com/questions/21255138/…
Daniel C

263

Знайдіть об’єкт, властивість якого "Y" має найбільшу цінність у масиві об'єктів

Одним із способів було б використання зменшення масиву ..

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 і вище)

Якщо вам не потрібно підтримувати IE (тільки Edge), або ви можете використовувати попередній компілятор, такий як Babel, ви можете використовувати сильніше синтаксис.

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

7
Це хороша відповідь, проте ви хочете передати початкове значення або ви отримаєте помилку, якщо масив даних порожній. тобто для індексу автоматичного збільшення об'єктів. const max = data.reduce((prev, current) => (prev.y > current.y) ? prev : current, 1)
juliangonzalez

2
Ви піднімете хорошу точку, я, мабуть, обрав би nullбільше 1.
Енді Полхілл

25
Зауважте, що це повертає об'єкт, який мав значення max, а не значення max від об'єкта. Це може бути або не бути тим, що ви хочете. У моєму випадку це було те, чого я хотів. +1
Іван

1
Гарна додаткова відповідь!
Легенди

Відмінна відповідь! Спочатку я вагався через зниження, але нам все одно доведеться ітератувати, так чому б і ні?
shapiro yaacov

146

чистий і простий ES6 (Babel)

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

Другий параметр повинен забезпечити значення за замовчуванням, якщо arrayToSearchInвоно порожнє.


8
також добре знати, що він повертає -Infinity( триєдне значення) для порожнього масиву
icl7126

1
Це підтримується в більшості сучасних браузерів без Babel.
Євген Кулабухов

20
оскільки він повертається -Infinityдля порожнього масиву, ви можете передати початкове значення Math.max(...state.allProjects.map(o => o.id), 1);
juliangonzalez

5
Це має бути прийнятою відповіддю зараз ... безумовно, більш тривалий підхід.
нік

1
обробляти випадок для зміни мінусових значень 0на arrayToSearchIn[0].y. Тимчасова складність Comparision: stackoverflow.com/a/53654364/860099
Каміль Kiełczewski

41

Порівняння дерева ONELINERS, які обробляють регістр мінус чисел (введення aмасиву):

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)

редагований приклад тут . Ідеї: maxA , maxB та maxC (побічний ефект maxB полягає в тому, що масив aзмінюється через те, що він sortє на місці).

Для більших масивів Math.max...буде винятком: Максимальний розмір стека викликів перевищений (Chrome 76.0.3809, Safari 12.1.2, дата 2019-09-13)


2
Дуже розумні методи для виконання поставленого завдання. Ніцца
TetraDev

На жаль, заборонено помилково і не вдалося скасувати, не редагуючи своє запитання, оскільки пройшло занадто багато часу.
Günter Zöchbauer

Спасибі чудовий аналіз.
d337

дякую за цю розбивку наявних варіантів та відмінності між підходами.
FistOfFury

одне, на що слід зазначити, що варіант B значно полегшує отримання всього об'єкта з максимальним yзначенням, залишаючи .yв кінці.
FistOfFury

23

Ну, спочатку слід проаналізувати рядок JSON, щоб ви могли легко отримати доступ до його членів:

var arr = $.parseJSON(str);

Використовуйте mapметод для вилучення значень:

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

Тоді ви можете використовувати масив у maxметоді:

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

Або як однолінійний:

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

15
Це не позначено тегамиjQuery
Робін ван Бален

1
@RobinvanBaalen: Так, ви праві. Однак він позначений JSON, але прийнята відповідь ігнорує це, і tobyodavies також видаляв це з теми питання ... Можливо, я повинен додати jquery до питання ...;)
Guffa

8
Не має великого значення, якщо @tobyodavies проігнорував той факт, що його позначено тегом json- він не використовує зовнішню бібліотеку JavaScript у своїй відповіді :)
Робін ван Бален

23

Я хотів би пояснити покрокову прийняту відповідь покроково:

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>');

Додаткова інформація:


Чудове пояснення! Це може бути трохи легше читати, якби це не було в коментарях до коду, але все-таки - чудова робота
Мартін

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
Чим це відрізняється від відповіді @ AndyPolhill?
Льюїс

7

якщо ви (або, хтось тут) вільний користуватися lodashбібліотекою утиліт, вона має функцію maxBy, яка була б дуже зручною у вашому випадку.

отже, ви можете використовувати як таке:

_.maxBy(jsonSlice, 'y');

6

Або простий сорт! Зберігаючи це реально :)

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

Хороша ідея +1 (найкоротший код), але є невелика помилка - зміни a.y<a.yна b.y-a.y. Час порівняння складності тут: stackoverflow.com/a/53654364/860099
Каміль Kiełczewski

2
Знаходження максимуму дорівнює O (n). Це О (nlogn). Написати простий код добре, доки ефективність не буде принесена в жертву.
Wildhammer

@Wildhammer - насправді мікрооптимізація варта того, коли у вас є докази того, що ви оптимізуєте вузьке місце. . У більшості випадків простий код є кращим вибором, ніж високоефективний код.
Kamil Kiełczewski

@ KamilKiełczewski Обидва порівняння масивів у цій статті мають однакову складність, різниця полягає в їхньому коефіцієнті. Наприклад, для пошуку рішення потрібні n одиниць часу, а інші - 7n. У теорії складності часу обидва ці є O (n). Про що ми говоримо в задачі пошуку max - це порівняння O (n) з O (n logn). Тепер, якщо ви можете гарантувати, що n не перевищує 10, то ви можете використовувати своє рішення, інакше алгоритм O (n) завжди є переможцем, а ефективність (досвід користувача) завжди передує досвіду розробника (запитайте людей у ​​галузі, вони вам це скажуть!) .
Wildhammer

@Wildhammer nope - навіть якщо у масиві n = 10000 елементів, користувач не побачить різниці - ТУТ . Оптимізація продуктивності хороша лише для вузьких місць програми (наприклад, вам потрібно обробити великі масиви) - але в більшості випадків фокус на ефективність - це неправильний підхід і витрата часу (= гроші). Це добре відома помилка підходу до коду - читайте докладніше: "мікрооптимізація"
Каміль Кишевський





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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.