Tìm giá trị tối đa của một thuộc tính trong một mảng các đối tượng


413

Tôi đang tìm kiếm một cách thực sự nhanh chóng, sạch sẽ và hiệu quả để có được giá trị "y" tối đa trong lát JSON sau đây:

[
  {
    "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
  }
]

Là một vòng lặp for là cách duy nhất để đi về nó? Tôi quan tâm đến việc sử dụng bằng cách nào đó Math.max.


4
Làm thế nào bạn sẽ trả về đối tượng và không chỉ giá trị attr tìm thấy?
Mike Lyons

1
Vì lợi ích của riêng tôi, tôi đã chạy một số thử nghiệm hoàn hảo nhanh chóng về điều này. jsperf.com/finding-the-max-value-an-array-of-objects
Andy Polhill

1
JSBin của các giải pháp jsbin.com/pagamujuge/edit?html,js,console
Andy Polhill

Câu trả lời:


739

Để tìm ygiá trị tối đa của các đối tượng trong array:

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

47
Bạn có thể mở rộng câu trả lời này để chỉ ra cách trả về đối tượng mà giá trị tối đa được tìm thấy không? Điều đó sẽ rất hữu ích, cảm ơn!
Mike Lyons

19
Đây là câu đố! hy vọng điều này sẽ giúp ích cho ai đó jsfiddle.net/45c5r246
mili

24
@MikeLyons nếu bạn vẫn quan tâm đến việc lấy đối tượng thực tế: jsfiddle.net/45c5r246/34
tobyodavies

11
Hãy phơi bày câu trả lời của bạn!
John William Domingo

12
FWIW sự hiểu biết của tôi là khi bạn gọi áp dụng trên một hàm, nó thực thi hàm với một giá trị được chỉ định cho thisvà một loạt các đối số được chỉ định dưới dạng một mảng. Thủ thuật là áp dụng biến mảng thành một chuỗi các đối số hàm thực tế. Vì vậy, trong trường hợp này, cuối cùng nó gọi Math.max(0.0265, 0.0250, 0.024, 0.031)với thishàm được thực thi Math. Tôi không thể hiểu tại sao nó nên Maththẳng thắn, tôi không nghĩ rằng chức năng yêu cầu hợp lệ this. Ồ và đây là một lời giải thích phù hợp: stackoverflow.com/questions/21255138/ từ
Daniel C

263

Tìm đối tượng có thuộc tính "Y" có giá trị lớn nhất trong một mảng các đối tượng

Một cách sẽ là sử dụng Array giảm ..

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 trở lên)

Nếu bạn không cần hỗ trợ IE (chỉ Edge) hoặc có thể sử dụng trình biên dịch trước như Babel, bạn có thể sử dụng cú pháp ngắn gọn hơn.

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

7
Đây là một câu trả lời tốt, tuy nhiên, bạn muốn chuyển một giá trị ban đầu hoặc bạn sẽ gặp lỗi trong trường hợp mảng dữ liệu trống. tức là cho một chỉ số tự động của các đối tượng. const max = data.reduce((prev, current) => (prev.y > current.y) ? prev : current, 1)
juliangonzalez

2
Bạn nêu lên một điểm tốt, tôi có thể sẽ chọn nullhơn 1.
Andy Polhill

25
Lưu ý rằng điều này trả về đối tượng có giá trị tối đa không phải giá trị tối đa từ đối tượng. Điều này có thể hoặc không thể là những gì bạn muốn. Trong trường hợp của tôi đó là những gì tôi muốn. +1
John

1
Câu trả lời bổ sung tốt!
Huyền thoại

Câu trả lời tuyệt vời! Lúc đầu, tôi do dự vì giảm, nhưng dù sao chúng ta cũng cần phải lặp lại, vậy tại sao không?
shapiro yaacov

146

ES6 sạch sẽ và đơn giản (Babel)

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

Tham số thứ hai sẽ đảm bảo giá trị mặc định nếu arrayToSearchIntrống.


8
cũng của nó tốt để biết rằng nó sẽ trả về -Infinity(một truthy giá trị) cho một mảng trống rỗng
icl7126

1
Điều này được hỗ trợ trong hầu hết các trình duyệt hiện đại mà không có Babel.
Eugene Kulabuhov

20
khi nó trả về -Infinitycho một mảng trống, bạn có thể vượt qua một giá trị ban đầu Math.max(...state.allProjects.map(o => o.id), 1);
juliangonzalez

5
Đây sẽ là câu trả lời được chấp nhận ngay bây giờ ... chắc chắn là cách tiếp cận ngắn gọn hơn.
nickb

1
để xử lý trường hợp cho các giá trị trừ thay đổi 0thành arrayToSearchIn[0].y. So sánh độ phức tạp thời gian: stackoverflow.com/a/53654364/860099
Kamil Kiełczewski

41

So sánh cây ONELINERS xử lý trường hợp số trừ (đầu vào trong amảng):

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)

ví dụ có thể chỉnh sửa ở đây . Các ý tưởng từ: maxA , maxBmaxC (tác dụng phụ của maxB là mảng đó bị athay đổi vì sortnằm tại chỗ).

Đối với các mảng lớn hơn, Math.max...ngoại lệ sẽ ném: vượt quá kích thước ngăn xếp cuộc gọi tối đa (Chrome 76.0.3809, Safari 12.1.2, ngày 2019-09-13)


2
Phương pháp rất thông minh để hoàn thành nhiệm vụ. Nice
TetraDev

Xin lỗi, bị bỏ qua do nhầm lẫn và không thể hoàn tác mà không chỉnh sửa câu hỏi của bạn vì đã mất quá nhiều thời gian.
Günter Zöchbauer

Cảm ơn phân tích tuyệt vời.
17:03

cảm ơn bạn về sự cố này của các tùy chọn có sẵn và sự khác biệt giữa các phương pháp.
FistOfFury

một điều cần chỉ ra là tùy chọn B giúp dễ dàng lấy toàn bộ đối tượng với ygiá trị tối đa bằng cách bỏ đi .yở cuối.
FistOfFury

23

Chà, trước tiên, bạn nên phân tích chuỗi JSON, để bạn có thể dễ dàng truy cập các thành viên của nó:

var arr = $.parseJSON(str);

Sử dụng mapphương pháp để trích xuất các giá trị:

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

Sau đó, bạn có thể sử dụng mảng trong maxphương thức:

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

Hoặc như một lớp lót:

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

15
Nó không được gắn thẻ jQuery
Robin van Baalen

1
@RobinvanBaalen: Vâng, bạn đã đúng. Tuy nhiên, nó được gắn thẻ JSON nhưng câu trả lời được chấp nhận bỏ qua điều đó và tobyodavies cũng loại bỏ nó khỏi chủ đề của câu hỏi ... Có lẽ tôi nên thêm câu hỏi vào câu hỏi ...;)
Guffa

8
Sẽ không có vấn đề gì nếu @tobyodavies bỏ qua thực tế rằng nó đã được gắn thẻ json- anh ấy không sử dụng thư viện javascript bên ngoài trong câu trả lời của mình :)
Robin van Baalen

23

Tôi muốn giải thích từng câu trả lời được chấp nhận ngắn gọn :

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

Thêm thông tin:


Giải thích tuyệt vời! Nó có thể dễ đọc hơn một chút nếu nó không có trong các nhận xét về mã, nhưng vẫn - công việc tuyệt vời
Martin

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
Điều này khác với câu trả lời của @ AndyPolhill như thế nào?
Lewis

7

nếu bạn (hoặc, ai đó ở đây) tự do sử dụng lodashthư viện tiện ích, nó có chức năng maxBy sẽ rất tiện dụng trong trường hợp của bạn.

do đó bạn có thể sử dụng như vậy:

_.maxBy(jsonSlice, 'y');

6

Hoặc một loại đơn giản! Giữ cho nó thật :)

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

Ý tưởng hay +1 (mã ngắn nhất), nhưng có một lỗi nhỏ - thay đổi a.y<a.ythành b.y-a.y. So sánh độ phức tạp thời gian ở đây: stackoverflow.com/a/53654364/860099
Kamil Kiełczewski

2
Tìm max là O (n). Đây là O (nlogn). Viết mã đơn giản là tốt miễn là hiệu quả không bị hy sinh.
Wildhammer

@Wildhammer - Thực sự tối ưu hóa vi mô rất đáng giá khi bạn có bằng chứng cho thấy bạn đang tối ưu hóa nút cổ chai. . Trong hầu hết các trường hợp, mã đơn giản là sự lựa chọn tốt hơn mã hiệu quả cao.
Kamil Kiełczewski

@ KamilKiełczewski Cả hai so sánh mảng trong bài viết đó có cùng độ phức tạp thời gian, sự khác biệt nằm ở hệ số của chúng. Chẳng hạn, người ta mất n đơn vị thời gian để tìm giải pháp trong khi người kia là 7n. Trong lý thuyết phức tạp thời gian, cả hai đều là O (n). Những gì chúng ta đang nói về vấn đề tìm max là so sánh O (n) với O (n logn). Bây giờ nếu bạn có thể đảm bảo n không vượt quá 10 thì bạn có thể sử dụng giải pháp của mình nếu không thuật toán O (n) luôn là người chiến thắng và hiệu suất (trải nghiệm người dùng) luôn đi trước trải nghiệm của nhà phát triển (hỏi người trong ngành, họ nói với bạn điều đó!) .
Wildhammer

@Wildhammer không - ngay cả khi mảng của bạn có n = 10000 phần tử người dùng sẽ không thấy sự khác biệt - bằng chứng TẠI ĐÂY . Tối ưu hóa hiệu suất chỉ tốt cho nút cổ chai ứng dụng (ví dụ: bạn cần xử lý các mảng lớn) - nhưng trong hầu hết các trường hợp, việc tập trung vào hiệu suất là cách tiếp cận sai và lãng phí thời gian (= tiền). Đây là lỗi tiếp cận mã nổi tiếng - đọc thêm: "tối ưu hóa vi mô"
Kamil Kiełczewski


2

Đây là giải pháp ngắn nhất (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
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.