ส่งกลับดัชนีของค่าที่ยิ่งใหญ่ที่สุดในอาร์เรย์


149

ฉันมีสิ่งนี้:

var arr = [0, 21, 22, 7];

วิธีใดที่ดีที่สุดในการคืนค่าดัชนีที่มีค่าสูงสุดเป็นตัวแปรอื่น


เพียงแค่ทราบคำตอบที่ให้ไว้ข้างต้นคำตอบจาก LanilT นั้นเร็วที่สุด! ดูเกณฑ์มาตรฐาน const indexOfMaxValue = arr.indexOf (Math.max (... arr)); jsben.ch/6nmd2
Cyprian Bergonia

@CyprianBergonia: ทำไมคำตอบของฉันจึงถูกแยกออกจากเกณฑ์มาตรฐานนั้น? มันเป็นอยู่ในปัจจุบันที่เร็วที่สุด: jsben.ch/sxcMG (ดีarr.indexOf(Math.max(...arr))เป็นยัง . คำตอบของฉัน แต่ฟังก์ชั่นหนึ่ง)
Ry-

คำตอบ:


179

นี่อาจเป็นวิธีที่ดีที่สุดเนื่องจากเชื่อถือได้และใช้ได้กับเบราว์เซอร์รุ่นเก่า:

function indexOfMax(arr) {
    if (arr.length === 0) {
        return -1;
    }

    var max = arr[0];
    var maxIndex = 0;

    for (var i = 1; i < arr.length; i++) {
        if (arr[i] > max) {
            maxIndex = i;
            max = arr[i];
        }
    }

    return maxIndex;
}

นอกจากนี้ยังมีซับเดียว:

let i = arr.indexOf(Math.max(...arr));

มันทำการเปรียบเทียบได้มากเป็นสองเท่าเท่าที่จำเป็นและจะโยนRangeErrorอาร์เรย์ขนาดใหญ่แม้ว่า ฉันชอบฟังก์ชั่น


1
ตกลงฟังก์ชันนี้จะส่งคืนดัชนีที่พบครั้งแรกสำหรับค่าที่มากที่สุด สมมติว่าฉันมีดัชนีมากกว่าหนึ่งดัชนีที่มีค่าสูงสุดเท่ากันฉันจะรับดัชนีเหล่านี้ทั้งหมดได้อย่างไร
ed1nh0

1
@ ed1nh0: วิธีง่ายๆคือทำบัตรหลายใบ ค้นหาสูงสุดด้วยแล้วดัชนีสูงสุดที่มีconst max = arr.reduce((m, n) => Math.max(m, n)) [...arr.keys()].filter(i => arr[i] === max)
Ry-

[...arr.keys()]แสดงข้อผิดพลาด:unexpected token
ed1nh0

@ ed1nh0: คุณกำหนดเป้าหมายเบราว์เซอร์ / สภาพแวดล้อมใด
Ry-

โครเมียม. ฉันใช้ VueJS และฉันเดาว่าปัญหาเกิดจาก webpack config
ed1nh0

85

ในบรรทัดเดียวและอาจเร็วกว่านั้นarr.indexOf(Math.max.apply(Math, arr)):

var a = [0, 21, 22, 7];
var indexOfMaxValue = a.reduce((iMax, x, i, arr) => x > arr[iMax] ? i : iMax, 0);

document.write("indexOfMaxValue = " + indexOfMaxValue); // prints "indexOfMaxValue = 2"

ที่ไหน:

  • iMax- ดัชนีที่ดีที่สุดจนถึงตอนนี้ (ดัชนีขององค์ประกอบสูงสุดในการวนซ้ำครั้งแรกiMax = 0เนื่องจากอาร์กิวเมนต์ที่สองreduce()คือ0เราไม่สามารถข้ามอาร์กิวเมนต์ที่สองreduce()ในกรณีของเราได้)
  • x - องค์ประกอบที่ทดสอบในปัจจุบันจากอาร์เรย์
  • i - ดัชนีที่ทดสอบในปัจจุบัน
  • arr- อาร์เรย์ของเรา ( [0, 21, 22, 7])

เกี่ยวกับreduce()วิธีการนี้ (จาก "JavaScript: The Definitive Guide" โดย David Flanagan):

ลด () รับสองอาร์กิวเมนต์ ประการแรกคือฟังก์ชั่นที่ดำเนินการลด หน้าที่ของฟังก์ชันการลดนี้คือการรวมหรือลดค่าสองค่าให้เป็นค่าเดียวและส่งคืนค่าที่ลดลงนั้น

ฟังก์ชันที่ใช้กับการลด () แตกต่างจากฟังก์ชันที่ใช้กับ forEach () และแผนที่ () ค่าดัชนีและอาร์เรย์ที่คุ้นเคยจะถูกส่งผ่านเป็นอาร์กิวเมนต์ที่สองสามและสี่ อาร์กิวเมนต์แรกคือผลการสะสมของการลดจนถึงขณะนี้ ในการเรียกใช้ฟังก์ชันครั้งแรกอาร์กิวเมนต์แรกนี้คือค่าเริ่มต้นที่คุณส่งผ่านเป็นอาร์กิวเมนต์ที่สองเพื่อลด () ในการโทรครั้งต่อ ๆ ไปเป็นค่าที่ส่งคืนโดยการเรียกใช้ฟังก์ชันก่อนหน้านี้

เมื่อคุณเรียกใช้การลด () โดยไม่มีค่าเริ่มต้นจะใช้องค์ประกอบแรกของอาร์เรย์เป็นค่าเริ่มต้น ซึ่งหมายความว่าการเรียกใช้ฟังก์ชันการลดครั้งแรกจะมีองค์ประกอบอาร์เรย์แรกและที่สองเป็นอาร์กิวเมนต์ที่หนึ่งและที่สอง


12
@traxium ในขณะที่คำอธิบายของคุณดีมาก แต่ตัวอย่างอาจชัดเจนกว่าสำหรับผู้ที่มีการเขียนโปรแกรมเชิงฟังก์ชันน้อยกว่าหากเราใช้ตัวแปรที่อธิบายได้มากขึ้น Say: arr.reduce((bestIndexSoFar, currentlyTestedValue, currentlyTestedIndex, array) => currentlyTestedValue > array[bestIndexSoFar] ? currentlyTestedIndex : bestIndexSoFar, 0);ซึ่งสามารถอธิบายเป็น: สำทับอาร์เรย์ที่เริ่มต้นจากดัชนี 0 (พารามิเตอร์ 2) ถ้าcurrentlyTestedValueสูงกว่ามูลค่าขององค์ประกอบที่ที่bestIndexSoFarแล้วกลับcurrentlyTestedIndexจะซ้ำไปเป็นbestIndexSoFar
niieani

1
@traxium คำตอบที่ยอดเยี่ยม ผมยังเห็นด้วยกับ @niieani this.methods.reduce((methodIndex, currentMethod, currentMethodIndex, methods) => currentMethod.price <= methods[methodIndex].price ? currentMethodIndex : methodIndex, 0)นี่เป็นตัวอย่างโลกแห่งความจริงที่ผมดำเนินการ:
Daniel

2
@DanielK คำตอบที่มีชื่อพารามิเตอร์ "เต็ม" จะไม่พอดีกับบรรทัดเดียว จะมีแถบเลื่อนแนวนอนปรากฏขึ้นและไม่สะดวกในการอ่านตัวอย่างข้อมูลขณะเลื่อนในแนวนอน ขอบคุณสำหรับคำแนะนำ ฉันแก้ไขคำตอบด้วยวิธีอื่น
traxium

@traxium +1 สำหรับโซลูชัน FP ในขณะที่มันซับซ้อนอย่างน่ากลัวสำหรับคนที่เพิ่งเริ่มต้นด้วย JS แต่โซลูชันของคุณก็เป็นหนึ่งในวิธีที่มีประสิทธิภาพมากที่สุดในการแก้ปัญหาของ OP
SeaWarrior404

ตามjsben.ch/ujXlkวิธีอื่นเร็วกว่า
VFDan


7

อีกวิธีหนึ่งของการใช้สูงสุดreduce:

[1,2,5,0,4].reduce((a,b,i) => a[0] < b ? [b,i] : a, [Number.MIN_VALUE,-1])
//[5,2]

สิ่งนี้จะส่งคืน[5e-324, -1]หากอาร์เรย์ว่างเปล่า หากคุณต้องการเพียงแค่ดัชนีให้ใส่[1]หลัง

นาทีผ่าน (เปลี่ยนเป็น>และMAX_VALUE):

[1,2,5,0,4].reduce((a,b,i) => a[0] > b ? [b,i] : a, [Number.MAX_VALUE,-1])
//[0, 3]

6

ถ้าฉันเข้าใจผิดฉันจะบอกว่าให้เขียนฟังก์ชันของคุณเอง

function findIndexOfGreatest(array) {
  var greatest;
  var indexOfGreatest;
  for (var i = 0; i < array.length; i++) {
    if (!greatest || array[i] > greatest) {
      greatest = array[i];
      indexOfGreatest = i;
    }
  }
  return indexOfGreatest;
}

ไม่จัดการให้ศูนย์เป็นค่าสูงสุด: findIndexOfGreatest( [-5, 0, -10, -1])ส่งกลับ 3 ...
traktor53

6

หากคุณใช้ขีดล่างคุณสามารถใช้ซับในสั้น ๆ นี้ได้:

_.indexOf(arr, _.max(arr))

ขั้นแรกจะพบค่าของรายการที่ใหญ่ที่สุดในอาร์เรย์ในกรณีนี้คือ 22 จากนั้นจะส่งคืนดัชนีที่ 22 อยู่ภายในอาร์เรย์ในกรณีนี้ 2


1
function findIndicesOf(haystack, needle)
{
    var indices = [];

    var j = 0;
    for (var i = 0; i < haystack.length; ++i) {
        if (haystack[i] == needle)
            indices[j++] = i;
    }
    return indices;
}

ผ่านarrayไปhaystackและจะMath.max(...array) needleสิ่งนี้จะให้องค์ประกอบสูงสุดทั้งหมดของอาร์เรย์และสามารถขยายได้มากขึ้น (เช่นคุณต้องหาค่าต่ำสุดด้วย)


1

ในการทำงานของ @VFDan ให้เสร็จสมบูรณ์ฉันได้เปรียบเทียบ 3 วิธี: หนึ่งที่ยอมรับ (ลูปที่กำหนดเอง) ลดและค้นหา (สูงสุด (arr)) บนอาร์เรย์ 10,000 ลอย

ผลลัพธ์บนโครเมียม 85 ลินุกซ์ (สูงกว่าดีกว่า):

  • ห่วงที่กำหนดเอง: 100%
  • ลด: 94.36%
  • indexOf (สูงสุด): 70%

ผลลัพธ์บน firefox 80 linux (สูงกว่าดีกว่า):

  • ห่วงที่กำหนดเอง: 100%
  • ลด: 96.39%
  • indexOf (สูงสุด): 31.16%

สรุป:

หากคุณต้องการให้โค้ดของคุณทำงานเร็วอย่าใช้ indexOf (max) ลดได้ แต่ใช้ลูปที่กำหนดเองหากคุณต้องการการแสดงที่ดีที่สุด

คุณสามารถเรียกใช้เกณฑ์มาตรฐานนี้บนเบราว์เซอร์อื่นโดยใช้ลิงก์นี้: https://jsben.ch/wkd4c


0

 var arr=[0,6,7,7,7];
 var largest=[0];
 //find the largest num;
 for(var i=0;i<arr.length;i++){
   var comp=(arr[i]-largest[0])>0;
      if(comp){
	  largest =[];
	  largest.push(arr[i]);
	  }
 }
 alert(largest )//7
 
 //find the index of 'arr'
 var arrIndex=[];
 for(var i=0;i<arr.length;i++){
    var comp=arr[i]-largest[0]==0;
	if(comp){
	arrIndex.push(i);
	}
 }
 alert(arrIndex);//[2,3,4]


0

แก้ไข: เมื่อหลายปีก่อนฉันให้คำตอบว่ามันไม่ชัดเจนเจาะจงเกินไปและซับซ้อนเกินไป ผมกำลังแก้ไข ฉันชอบคำตอบที่ใช้งานได้ข้างต้นสำหรับปัจจัยที่เป็นระเบียบ แต่อ่านไม่ออก แต่ถ้าฉันคุ้นเคยกับจาวาสคริปต์มากกว่าฉันก็อาจจะชอบมันด้วยเช่นกัน

รหัสหลอก:

ติดตามดัชนีที่มีค่ามากที่สุด สมมติว่าดัชนี 0 มีขนาดใหญ่ที่สุดในตอนแรก เปรียบเทียบกับดัชนีปัจจุบัน อัปเดตดัชนีที่มีค่ามากที่สุดหากจำเป็น

รหัส:

var mountains = [3, 1, 5, 9, 4];

function largestIndex(array){
  var counter = 1;
  var max = 0;

  for(counter; counter < array.length; counter++){
    if(array[max] < array[counter]){
        max = counter;
    }
  }
  return max;
}

console.log("index with largest value is: " +largestIndex(mountains));
// index with largest value is: 3

0

หากคุณสร้างสำเนาของอาร์เรย์และเรียงลำดับจากมากไปหาน้อยองค์ประกอบแรกของสำเนาจะมีขนาดใหญ่ที่สุด กว่าคุณจะพบดัชนีในอาร์เรย์เดิม

var sorted = [...arr].sort((a,b) => b - a)
arr.indexOf(sorted[0])

ความซับซ้อนของเวลาคือ O (n) สำหรับสำเนา O (n * log (n)) สำหรับการเรียงลำดับและ O (n) สำหรับ indexOf

หากคุณต้องการทำเร็วขึ้นคำตอบของ Ry คือ O (n)


-1

เวอร์ชันเสถียรของฟังก์ชันนี้มีลักษณะดังนี้:

// not defined for empty array
function max_index(elements) {
    var i = 1;
    var mi = 0;
    while (i < elements.length) {
        if (!(elements[i] < elements[mi]))
            mi = i;
        i += 1;
    }
    return mi;
}

“ เสถียร” หมายความว่าอย่างไรในบริบทนี้
Ry-

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