Trả về chỉ số có giá trị lớn nhất trong một mảng


138

Tôi có cái này:

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

Cách tốt nhất để trả chỉ số của giá trị cao nhất vào một biến khác là gì?


21
Đó không phải là một bản sao, hãy đọc câu hỏi NGAY @Dancrumb Cách SO hoạt động là tôi đăng câu hỏi này và trong nhiều thập kỷ tới mọi người sẽ tìm thấy nó, đọc nó và biết ơn những thông tin mà những người đóng góp đã đăng dưới đây!
Stephen

1
@ Ngược lại, ngược lại, nếu bạn đọc Câu hỏi thường gặp này , bạn sẽ thấy những câu hỏi chủ quan (chẳng hạn như câu hỏi bắt đầu "Cách tốt nhất ...") rõ ràng là không được khuyến khích. Tuy nhiên, SO là một cộng đồng, vì vậy, cộng đồng sẽ xác định xem câu hỏi này có nên được đóng lại hay không.
Dancrumb

6
Tìm số lớn nhất trong một mảng không giống như tìm chỉ số của số lớn nhất trong một mảng. Do đó, câu hỏi này không phải là một bản sao của tài liệu tham khảo đó được đăng dưới dạng trùng lặp.
Fzs2

15
Đây KHÔNG phải là một bản sao - hoặc ít nhất là không phải của câu hỏi được tham chiếu. Tôi không thể hiểu các ý kiến ​​trái chiều về điều này - nói rằng bạn không thể hỏi SO cách tốt nhất để làm điều gì đó là lố bịch và không có ví dụ mã nào được yêu cầu cho một câu hỏi ngắn gọn như vậy. Làm thế nào mà 'bản sao' được tham chiếu có +30 phiếu, và câu hỏi NHƯNG KHÁC NHAU song song này, được hỏi theo một kiểu rất giống nhau, có -3 phiếu? Vui lòng đọc lại câu hỏi và xóa phiếu đánh dấu trùng lặp của bạn. "Index of" là cụm từ chính bạn cần phát hiện trong tiêu đề câu hỏi.
bánh kếp

@Dancrumb Lời khuyên hiện tại trong stackoverflow.com/help/dont-ask không khuyến khích các câu hỏi chủ quan chỉ khi mọi câu trả lời đều có giá trị như nhau. Trong trường hợp này, "tốt nhất" rõ ràng có thể được đánh giá về hiệu suất, độ căng và tính biểu cảm.
dùng234461

Câu trả lời:


165

Đây có lẽ là cách tốt nhất, vì nó đáng tin cậy và hoạt động trên các trình duyệt cũ:

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;
}

Ngoài ra còn có một lớp lót này:

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

Nó thực hiện gấp đôi số lần so sánh khi cần thiết và sẽ đưa ra một RangeErrormảng lớn. Tôi sẽ bám vào chức năng.


1
Ok hàm này trả về chỉ mục bắt gặp đầu tiên cho giá trị lớn nhất. Giả sử tôi có nhiều hơn một chỉ mục có cùng giá trị cao nhất, làm thế nào để tôi có được tất cả các chỉ mục này?
ed1nh0

1
@ ed1nh0: Cách dễ dàng là thực hiện nhiều đường chuyền. Tìm max với const max = arr.reduce((m, n) => Math.max(m, n)), sau đó các chỉ số của max là [...arr.keys()].filter(i => arr[i] === max).
Ry-

[...arr.keys()]xuất ra một lỗi:unexpected token
ed1nh0

@ ed1nh0: Bạn đang nhắm mục tiêu trình duyệt / môi trường nào?
Ry-

Trình duyệt Chrome. Tôi đang sử dụng VueJS và tôi đoán vấn đề là một cái gì đó trên cấu hình webpack.
ed1nh0

81

Trong một dòng và có thể nhanh hơn sau đó 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"

Ở đâu:

  • iMax- chỉ mục tốt nhất cho đến nay (chỉ mục của phần tử max cho đến nay, trong lần lặp đầu tiên iMax = 0vì đối số thứ hai reduce()0, chúng ta không thể bỏ qua đối số thứ hai reduce()trong trường hợp của chúng ta)
  • x - phần tử hiện đang được thử nghiệm từ mảng
  • i - chỉ số hiện đang được thử nghiệm
  • arr- mảng của chúng tôi ( [0, 21, 22, 7])

Về reduce()phương pháp (từ "JavaScript: Hướng dẫn dứt khoát" của David Flanagan):

giảm () mất hai đối số. Đầu tiên là chức năng thực hiện các hoạt động giảm. Nhiệm vụ của hàm giảm này là bằng cách nào đó kết hợp hoặc giảm hai giá trị thành một giá trị duy nhất và trả về giá trị giảm đó.

Các hàm được sử dụng với less () khác với các hàm được sử dụng với forEach () và map (). Giá trị quen thuộc, chỉ mục và giá trị mảng được truyền dưới dạng đối số thứ hai, thứ ba và thứ tư. Đối số đầu tiên là kết quả tích lũy của việc giảm cho đến nay. Trong lệnh gọi đầu tiên đến hàm, đối số đầu tiên này là giá trị ban đầu bạn đã chuyển làm đối số thứ hai để giảm (). Trong các cuộc gọi tiếp theo, nó là giá trị được trả về bởi lệnh gọi trước đó của hàm.

Khi bạn gọi less () không có giá trị ban đầu, nó sử dụng phần tử đầu tiên của mảng làm giá trị ban đầu. Điều này có nghĩa là lệnh gọi đầu tiên đến hàm rút gọn sẽ có các phần tử mảng thứ nhất và thứ hai làm đối số thứ nhất và thứ hai.


12
@traxium Mặc dù lời giải thích của bạn rất hay, ví dụ có thể rõ ràng hơn cho những người ít tham gia vào lập trình chức năng nếu chúng ta sử dụng nhiều biến mô tả hơn. Nói: arr.reduce((bestIndexSoFar, currentlyTestedValue, currentlyTestedIndex, array) => currentlyTestedValue > array[bestIndexSoFar] ? currentlyTestedIndex : bestIndexSoFar, 0);, có thể được mô tả như: lặp mảng bắt đầu từ chỉ số 0 (tham số thứ 2), nếu currentlyTestedValue là cao hơn giá trị của phần tử tại bestIndexSoFar , sau đó trả lại currentlyTestedIndex đến phiên bản kế tiếp như bestIndexSoFar .
niieani

1
@traxium Câu trả lời tuyệt vời. Tôi cũng đồng ý với @niieani Đây là một ví dụ thực tế mà tôi đã triển khai : this.methods.reduce((methodIndex, currentMethod, currentMethodIndex, methods) => currentMethod.price <= methods[methodIndex].price ? currentMethodIndex : methodIndex, 0).
Daniel

2
@DanielK, Câu trả lời với tên tham số "đầy đủ" sẽ không khớp với một dòng stackoverflow. Sẽ xuất hiện một thanh cuộn ngang và sẽ không thuận tiện khi đọc đoạn trích trong khi cuộn theo chiều ngang. Dù sao cũng cảm ơn những lời đề nghị. Tôi chỉnh sửa câu trả lời theo cách khác.
traxium

@traxium +1 cho giải pháp FP. Mặc dù rất phức tạp đối với một người mới bắt đầu với JS, nhưng giải pháp của bạn cũng là một trong những giải pháp hiệu quả nhất để giải quyết vấn đề của OP.
SeaWar Warrior404

Theo jsben.ch/ujXlk , phương pháp khác nhanh hơn.
VFDan

46

Đây là một giải pháp khác, Nếu bạn đang sử dụng ES6 bằng toán tử trải rộng:

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

const indexOfMaxValue = arr.indexOf(Math.max(...arr));

6

Trừ khi tôi nhầm, tôi sẽ nói đó là viết chức năng của riêng bạn.

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;
}

6

Nếu bạn đang sử dụng dấu gạch dưới, bạn có thể sử dụng một lớp lót ngắn đẹp này:

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

Đầu tiên nó sẽ tìm giá trị của mục lớn nhất trong mảng, trong trường hợp này 22. Sau đó, nó sẽ trả về chỉ mục trong đó 22 nằm trong mảng, trong trường hợp này là 2.


6

Một giải pháp tối đa khác sử dụng reduce:

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

Điều này trả về [5e-324, -1]nếu mảng trống. Nếu bạn chỉ muốn chỉ mục, đặt [1]sau.

Tối thiểu qua (Thay đổi thành >MAX_VALUE):

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

1

EDIT: Nhiều năm trước tôi đã đưa ra một câu trả lời cho điều này quá thô thiển, quá cụ thể và quá phức tạp. Vì vậy, tôi đang chỉnh sửa nó. Tôi ủng hộ các câu trả lời chức năng ở trên cho yếu tố gọn gàng của họ nhưng không dễ đọc; nhưng nếu tôi quen thuộc hơn với javascript thì tôi cũng có thể thích chúng vì điều đó.

Mã giả:

Theo dõi chỉ số có chứa giá trị lớn nhất. Giả sử chỉ số 0 là lớn nhất ban đầu. So sánh với chỉ số hiện tại. Cập nhật chỉ số với giá trị lớn nhất nếu cần thiết.

Mã số:

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

Cảm ơn! Tôi đã phải lộn xộn với nó hơn nữa.
ross studtman

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;
}

vượt qua arrayđể haystackMath.max(...array)để needle. Điều này sẽ cung cấp cho tất cả các phần tử tối đa của mảng và nó có thể mở rộng hơn (ví dụ: bạn cũng cần tìm các giá trị tối thiểu)


1

Nếu bạn tạo một bản sao của mảng và sắp xếp nó giảm dần, phần tử đầu tiên của bản sao sẽ là phần lớn nhất. Hơn bạn có thể tìm thấy chỉ mục của nó trong mảng ban đầu.

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

Độ phức tạp thời gian là O (n) cho bản sao, O (n * log (n)) để sắp xếp và O (n) cho indexOf.

Nếu bạn cần làm nhanh hơn, câu trả lời của Ry là O (n).


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]


-1

Một phiên bản ổn định của chức năng này trông như thế này:

// 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;
}

Không ổn định có nghĩa là gì trong bối cảnh này?
Ry-

Tôi đoán anh ta có nghĩa là "phù hợp"
Ikbel

-5

Đơn giản

maxarr: function(){
let maxval = 0;
let maxindex = null;
for (i = 0; i < arr.length; i++){
if (arr[i] > maxval) {
maxval = arr[i];
maxindex = i;
}
}
}

Xin lỗi tôi đã không đọc bài viết rõ ràng bây giờ tôi sẽ cập nhật mã
vidhyesh

vui lòng giải thích câu trả lời của bạn xa hơn một chút (giúp loại bỏ các downvote) và cũng cố gắng phân biệt nó với câu trả lời khác (ieeg: sử dụng ít tài nguyên hơn hoặc nhanh hơn trong tính toán ... vv). (Kết thúc đánh giá câu trả lời chất lượng thấp).
ZF007

Điều này không trả về chỉ số của giá trị tối đa; Điều này chỉ trả về giá trị dương tối đa .
Cœur
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.