การหาค่าสูงสุดของคุณสมบัติในอาร์เรย์ของวัตถุ


413

ฉันกำลังมองหาวิธีที่รวดเร็วสะอาดและมีประสิทธิภาพในการรับค่า "y" สูงสุดในชิ้นส่วน 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
  }
]

for-loop เป็นวิธีเดียวที่จะไปเกี่ยวกับมันได้หรือไม่ Math.maxฉันกระตือรือร้นในการใช้อย่างใด


4
คุณจะคืนค่าออบเจ็กต์ไม่ใช่แค่ค่า min attr ที่พบได้อย่างไร
Mike Lyons

1
เพื่อประโยชน์ของฉันเองฉันได้ทำการทดสอบแบบรวดเร็วในเรื่องนี้ jsperf.com/finding-the-max-value-an-array-of-objects
Andy Polhill

1
JSBin ของโซลูชันjsbin.com/pagamujuge/edit?html,js,console
Andy Polhill

คำตอบ:


739

วิธีค้นหาyค่าสูงสุดของวัตถุในarray:

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

47
คุณสามารถขยายคำตอบนี้เพื่อแสดงวิธีคืนวัตถุที่พบค่าสูงสุดได้หรือไม่? นั่นจะเป็นประโยชน์มากขอบคุณ!
Mike Lyons

19
นี่คือซอ! หวังว่าสิ่งนี้จะช่วยให้ใครบางคนjsfiddle.net/45c5r246
mili

24
@ MikeLyons หากคุณยังสนใจเกี่ยวกับการรับวัตถุจริง: jsfiddle.net/45c5r246/34
tobyodavies

11
โปรดตอบคำถามของคุณ!
John William Domingo

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" มีค่ามากที่สุดในอาร์เรย์ของวัตถุ

วิธีหนึ่งก็คือใช้ Array ลด ..

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
Andy Polhill

25
โปรดทราบว่าสิ่งนี้จะส่งคืนวัตถุที่มีค่าสูงสุดไม่ใช่ค่าสูงสุดจากวัตถุ นี่อาจเป็นหรือไม่ใช่สิ่งที่คุณต้องการ ในกรณีของฉันมันเป็นสิ่งที่ฉันต้องการ +1
John

1
คำตอบที่ดีเสริม!
ตำนาน

คำตอบที่ยอดเยี่ยม! ตอนแรกฉันลังเลเนื่องจากการลดลง แต่เราจะต้องทำซ้ำแล้วทำไมล่ะ
shapiro yaacov

146

สะอาดและเรียบง่าย ES6 (Babel)

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

พารามิเตอร์ที่สองควรตรวจสอบให้แน่ใจว่าค่าเริ่มต้นหากarrayToSearchInว่างเปล่า


8
ยังเป็นเรื่องที่ดีที่จะรู้ว่ามันจะกลับ-Infinity(กtruthyค่า) สำหรับอาร์เรย์ที่ว่างเปล่า
icl7126

1
สิ่งนี้ได้รับการสนับสนุนในเบราว์เซอร์ที่ทันสมัยที่สุดโดยไม่มี Babel เลย
Eugene Kulabuhov

20
ในขณะที่มันส่งกลับ-Infinityสำหรับอาร์เรย์ที่ว่างเปล่าคุณสามารถส่งผ่านค่าเริ่มต้น Math.max(...state.allProjects.map(o => o.id), 1);
juliangonzalez

5
นี่ควรเป็นคำตอบที่ได้รับการยอมรับในตอนนี้ ...
nickb

1
กับกรณีที่จับสำหรับลบค่าเปลี่ยนแปลงไป0 arrayToSearchIn[0].yการเปรียบเทียบความซับซ้อนของเวลา: stackoverflow.com/a/53654364/860099
Kamil Kiełczewski

41

การเปรียบเทียบ tree 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

ขออภัย downvote โดยไม่ได้ตั้งใจและไม่สามารถยกเลิกได้โดยไม่ต้องแก้ไขคำถามของคุณเนื่องจากเวลาผ่านไปนานเกินไป
GünterZö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
Robin van Baalen

1
@RobinvanBaalen: ใช่คุณพูดถูก อย่างไรก็ตามแท็กด้วย JSON แต่คำตอบที่ยอมรับนั้นไม่สนใจและโทบีโดวีส์ก็ลบมันออกจากหัวข้อคำถาม ... บางทีฉันควรเพิ่ม jquery ให้กับคำถาม ... ;)
Guffa

8
มันไม่สำคัญมากถ้า @tobyodavies ละเลยข้อเท็จจริงที่ว่ามันถูกแท็กjson- เขาไม่ได้ใช้ห้องสมุดจาวาสคริปต์ภายนอกในคำตอบของเขา :)
โรบินฟาน Baalen

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

ข้อมูลเพิ่มเติม:


คำอธิบายที่ดี! มันอาจจะง่ายกว่าที่จะอ่านถ้ามันไม่ได้อยู่ในความคิดเห็นของรหัส แต่ยัง - งานที่ดี
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
สิ่งนี้แตกต่างจากคำตอบของ @ 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
Kamil Kiełczewski

2
การหาค่าสูงสุดคือ O (n) นี่คือ O (nlogn) การเขียนโค้ดอย่างง่ายนั้นดีตราบใดที่ประสิทธิภาพยังไม่ลดลง
Wildhammer

@Wildhammer - การเพิ่มประสิทธิภาพ Microจริง ๆ แล้วคุ้มค่าเมื่อคุณมีหลักฐานว่าคุณเพิ่มประสิทธิภาพของคอขวด . ในกรณีส่วนใหญ่รหัสง่าย ๆ เป็นทางเลือกที่ดีกว่ารหัสที่มีประสิทธิภาพสูง
Kamil Kiełczewski

@ KamilKiełczewskiการเปรียบเทียบอาร์เรย์ทั้งสองในบทความนั้นมีความซับซ้อนในเวลาเดียวกันความแตกต่างอยู่ในสัมประสิทธิ์ของพวกเขา ตัวอย่างเช่นหนึ่งหน่วยใช้เวลา n เพื่อค้นหาวิธีแก้ปัญหาในขณะที่อีกหน่วยหนึ่งคือ 7n ในทฤษฎีความซับซ้อนของเวลาทั้งสองนี้เป็น O (n) สิ่งที่เรากำลังพูดถึงในปัญหาของการหาค่าสูงสุดคือการเปรียบเทียบ O (n) กับ O (n logn) ตอนนี้ถ้าคุณรับประกันได้ว่า n ไม่เกิน 10 คุณสามารถใช้วิธีแก้ปัญหาของคุณไม่เช่นนั้น O (n) อัลกอริทึมจะเป็นผู้ชนะและประสิทธิภาพ (ประสบการณ์ผู้ใช้) เสมอก่อนประสบการณ์นักพัฒนา (ถามคนในอุตสาหกรรมพวกเขาบอกคุณว่า!) .
Wildhammer

@Wildhammer Nope - แม้ว่าอาร์เรย์ของคุณมีผู้ใช้ n = 10000 องค์ประกอบจะไม่เห็นความแตกต่าง - หลักฐานที่นี่ การเพิ่มประสิทธิภาพให้ดีนั้นเหมาะสำหรับคอขวดของแอป (เช่นคุณต้องประมวลผลอาร์เรย์จำนวนมาก) แต่ในกรณีส่วนใหญ่การมุ่งเน้นประสิทธิภาพเป็นวิธีที่ไม่ถูกต้องและเสียเวลา (= เงิน) นี่เป็นข้อผิดพลาดของวิธีการใช้รหัสที่รู้จักกันดี - อ่านเพิ่มเติม: "micro-optimization"
Kamil Kiełczewski





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
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.