Tìm phần tử tối thiểu / tối đa của một mảng trong JavaScript


779

Làm cách nào tôi có thể dễ dàng có được phần tử tối thiểu hoặc tối đa của một mảng JavaScript?

Ví dụ Psuedocode:

let array = [100, 0, 50]

array.min() //=> 0
array.max() //=> 100

93
Lưu ý: Với ECMAScript 6, bạn có thể sử dụng toán tử trải rộng mới (ba dấu chấm ...:) với Math.max()như thế này : Math.max(...[2, 5, 16, 1]). Xem câu trả lời của tôi được thực hiện từ tài liệu MDN .
totymedli

1
Xem xét đánh dấu một câu trả lời là được chấp nhận.
Alex

đây là một điểm chuẩn để so sánh tốc độ của những cách phổ biến nhất để làm điều đó: jsben.ch/#/1QuTg
EscapeNetscape

es6 về cơ bản là tuyệt vời! :)
datdinhquoc

Không có ES6 Math.max.apply(null, [2,5,16,1])
Tomer

Câu trả lời:


828

Làm thế nào về việc tăng đối tượng Array tích hợp để sử dụng Math.max/ Math.minthay vào đó:

Array.prototype.max = function() {
  return Math.max.apply(null, this);
};

Array.prototype.min = function() {
  return Math.min.apply(null, this);
};

Đây là một JSFiddle .

Tăng cường biện pháp xây dựng-in có thể gây ra va chạm với các thư viện khác (Một số người xem), vì vậy bạn có thể thoải mái hơn với chỉ apply'ing Math.xxx()để mảng của bạn trực tiếp:

var min = Math.min.apply(null, arr),
    max = Math.max.apply(null, arr);

Cách khác, giả sử trình duyệt của bạn hỗ trợ ECMAScript 6, bạn có thể sử dụng toán tử trải rộng có chức năng tương tự như applyphương thức:

var min = Math.min( ...arr ),
    max = Math.max( ...arr );

8
@HankH: vượt qua nullhoặc Mathhoặc {}bất cứ điều gì đến apply()hoặc call()không có liên quan đến kết quả. Math.maxkhông nên cũng không nên tham khảo thisnội bộ.
Roatin Marth

31
Là một lập trình viên C #, tôi yêu cầu các câu hỏi đánh máy mạnh.
ChaosPandion

7
Chỉ chia sẻ một lỗi jQuery tôi đã làm với đoạn mã trên khiến tôi mất nhiều thời gian để gỡ lỗi. Một mảng jquery hoạt động tốt trên mọi thứ trừ iPad. Tôi đã phải chuyển đổi mảng thành một mảng gốc thực sự để nó hoạt động. Chỉ ảnh hưởng đến thiết bị duy nhất vì một số lý doMath.max.apply(null, $.makeArray(array));
Forrest

11
Tôi đã hạ cấp, vì cách tiếp cận được đề xuất sẽ tiêu thụ bộ nhớ O (n) trong khung ngăn xếp và kết quả là sự cố trên các mảng lớn. Trong trường hợp của tôi, chỉ khoảng 130000 số là đủ để đánh sập nodejs.
Alexey Timanovsky 12/2/2015

14
Đừng gia tăng các nguyên mẫu tích hợp như thế này. Nó không chỉ là xung đột với các thư viện khác; đó cũng là về tiềm năng mà chính trình duyệt cung cấp .maxhoặc .minphương thức trong tương lai. Kịch bản hoàn hảo thực tế: Bạn sử dụng câu trả lời này. Trong năm 2016, ES7 hoặc ES8 spec Array.maxArray.min. Không giống như phiên bản này, chúng hoạt động trên chuỗi. Đồng nghiệp tương lai của bạn cố gắng lấy chuỗi mới nhất theo thứ tự bảng chữ cái trong một mảng với .max()phương thức gốc được chứng minh bằng tài liệu hiện có , nhưng bí ẩn NaN. Vài giờ sau, cô tìm thấy mã này, chạy a git blamevà nguyền rủa tên của bạn.
Đánh dấu Amery

362
var max_of_array = Math.max.apply(Math, array);

Để thảo luận đầy đủ, hãy xem: http://aaroncrane.co.uk/2008/11/javascript_max_api/


13
Sự khác biệt giữa Math.max.apply(Math, array)và là Math.max.apply(null, array)gì? Blog nói "... bạn cũng phải nói lại một cách thừa thãi maxthuộc về Math...", nhưng có vẻ như tôi không phải làm như vậy (bằng cách đặt đối số đầu tiên applylà as null).
ziyuang

9
@ziyuang Khi bạn gọi nó như thế nào Math.max(a,b), Mathđược thông qua dưới dạng thisgiá trị, vì vậy có thể có ý nghĩa tương tự khi gọi với apply. Nhưng Math.maxkhông sử dụng thisgiá trị, vì vậy bạn có thể vượt qua bất kỳ giá trị nào bạn muốn.
Oriol

199

Đối với các mảng lớn (~ 10⁷ phần tử) Math.minMath.maxcả hai đều tạo ra lỗi sau trong Node.js.

RangeError: Vượt quá kích thước ngăn xếp cuộc gọi tối đa

Một giải pháp mạnh mẽ hơn là không thêm mọi phần tử vào ngăn xếp cuộc gọi mà thay vào đó là truyền một mảng:

function arrayMin(arr) {
  return arr.reduce(function (p, v) {
    return ( p < v ? p : v );
  });
}

function arrayMax(arr) {
  return arr.reduce(function (p, v) {
    return ( p > v ? p : v );
  });
}

Nếu bạn lo lắng về tốc độ, đoạn mã sau nhanh hơn ~ 3 lần Math.max.applytrên máy tính của tôi. Xem http://jsperf.com/min-and-max-in-array/2 .

function arrayMin(arr) {
  var len = arr.length, min = Infinity;
  while (len--) {
    if (arr[len] < min) {
      min = arr[len];
    }
  }
  return min;
};

function arrayMax(arr) {
  var len = arr.length, max = -Infinity;
  while (len--) {
    if (arr[len] > max) {
      max = arr[len];
    }
  }
  return max;
};

Nếu mảng của bạn chứa chuỗi thay vì số, bạn cũng cần ép buộc chúng thành số. Đoạn mã dưới đây thực hiện điều đó, nhưng nó làm chậm mã xuống ~ 10 lần trên máy của tôi. Xem http://jsperf.com/min-and-max-in-array/3 .

function arrayMin(arr) {
  var len = arr.length, min = Infinity;
  while (len--) {
    if (Number(arr[len]) < min) {
      min = Number(arr[len]);
    }
  }
  return min;
};

function arrayMax(arr) {
  var len = arr.length, max = -Infinity;
  while (len--) {
    if (Number(arr[len]) > max) {
      max = Number(arr[len]);
    }
  }
  return max;
};

gán minmaxcho phần tử cuối cùng và giảm số lần lặp xuống 1 ( while(--len));)
Venugopal

@Venugopal sau đó bạn cần kiểm tra đặc biệt để xem mảng có trống không và trả về +/- Infinity
Linus Unnebäck

2
Lạ thật ... Tôi đã truy cập trang web được liên kết ... và thử nghiệm trong Firefox 51.0.0 / Mac OS X 10.12.0, cách tiếp cận dựa trên giảm chậm hơn 30% so với dựa trên vòng lặp ... kết quả rất khác nhau
Pierpaolo Cira

2
very different results bạn đã làm điều này 5 năm sau)
Алексей Лещук

1
Năm 2019 các reducegiải pháp là chậm nhất. Ngay cả khi bạn làm việc với một mảng có hàng triệu phần tử, tốt hơnsử dụng tiêu chuẩn cho vòng lặp . Xem câu trả lời của tôi để biết thêm.
totymedli

152

Sử dụng toán tử trải rộng (ES6)

Math.max(...array);  // the same with "min" => Math.min(...array);


8
Giải pháp này đã được cung cấp bởi nhiều câu trả lời khác .
totymedli

15
Math.max (... []) = -Tất cả. hahaha 😂😂😂
David Portabella

@DavidPortabella không chắc tại sao lại buồn cười. Đó là cách nó hoạt động theo đặc điểm kỹ thuật :If no arguments are given, the result is -∞.
Patrick Roberts

3
vâng, ý tôi là đặc tả javascript thật kinh khủng. Dường như rõ ràng là số không có số không thể được tính toán. Trong các ngôn ngữ lập trình nghiêm túc khác, chẳng hạn như Scala, yêu cầu tối thiểu của một mảng trống sẽ ném ra một ngoại lệ.
David Portabella

3
Scala dành cho những người cần một chiếc máy để nói với họ rằng họ đã làm sai
thedanotto

106

tl; dr

// For regular arrays:
var max = Math.max(...arrayOfNumbers);

// For arrays with tens of thousands of items:
let max = testArray[0];
for (let i = 1; i < testArrayLength; ++i) {
  if (testArray[i] > max) {
    max = testArray[i];
  }
}

Giải pháp MDN

Các tài liệu MDN chính thức vềMath.max() vấn đề này đã bao gồm vấn đề này:

Hàm sau sử dụng Function.prototype.apply () để tìm phần tử tối đa trong một mảng số. getMaxOfArray([1, 2, 3])tương đương với Math.max(1, 2, 3), nhưng bạn có thể sử dụng getMaxOfArray()trên các mảng được xây dựng theo chương trình với mọi kích thước.

function getMaxOfArray(numArray) {
    return Math.max.apply(null, numArray);
}

Hoặc với toán tử trải rộng mới , việc lấy tối đa của một mảng trở nên dễ dàng hơn rất nhiều.

var arr = [1, 2, 3];
var max = Math.max(...arr);

Kích thước tối đa của một mảng

Theo MDN, các applygiải pháp lan truyền giới hạn 65536 xuất phát từ giới hạn số lượng đối số tối đa:

Nhưng hãy cẩn thận: khi sử dụng áp dụng theo cách này, bạn sẽ gặp rủi ro vượt quá giới hạn độ dài đối số của công cụ JavaScript. Hậu quả của việc áp dụng một hàm có quá nhiều đối số (nghĩ rằng hơn hàng chục nghìn đối số) khác nhau giữa các công cụ ( JavaScriptCore có giới hạn đối số được mã hóa cứng là 65536 ), bởi vì giới hạn (thực sự là bản chất của bất kỳ ngăn xếp quá lớn nào hành vi) là không xác định. Một số động cơ sẽ ném một ngoại lệ. Nghiêm trọng hơn, những người khác sẽ tùy ý giới hạn số lượng đối số thực sự được truyền cho hàm được áp dụng. Để minh họa trường hợp sau này: nếu một công cụ như vậy có giới hạn bốn đối số (giới hạn thực tế dĩ nhiên cao hơn đáng kể), thì sẽ như thể các đối số 5, 6, 2, 3 đã được thông qua để áp dụng trong các ví dụ trên, chứ không phải là mảng đầy đủ.

Họ thậm chí còn cung cấp một giải pháp lai không thực sự có hiệu suất tốt so với các giải pháp khác. Xem kiểm tra hiệu suất dưới đây để biết thêm.

Năm 2019 giới hạn thực tế là kích thước tối đa của ngăn xếp cuộc gọi . Đối với các trình duyệt máy tính để bàn dựa trên Chromium hiện đại, điều này có nghĩa là khi tìm thấy min / max có applyhoặc trải rộng, thực tế kích thước tối đa cho các số chỉ các mảng là ~ 120000 . Ở trên này, sẽ có một lỗi tràn ngăn xếp và lỗi sau sẽ được đưa ra:

RangeError: Vượt quá kích thước ngăn xếp cuộc gọi tối đa

Với tập lệnh bên dưới (dựa trên bài đăng trên blog này ), bằng cách bắt lỗi đó, bạn có thể tính giới hạn cho môi trường cụ thể của mình.

Cảnh báo! Chạy tập lệnh này mất thời gian và tùy thuộc vào hiệu suất của hệ thống của bạn, nó có thể làm chậm hoặc làm sập trình duyệt / hệ thống của bạn!

let testArray = Array.from({length: 10000}, () => Math.floor(Math.random() * 2000000));
for (i = 10000; i < 1000000; ++i) {
  testArray.push(Math.floor(Math.random() * 2000000));
  try {
    Math.max.apply(null, testArray);
  } catch (e) {
    console.log(i);
    break;
  }
}

Hiệu suất trên mảng lớn

Dựa trên thử nghiệm trong nhận xét của EscapeNetscape , tôi đã tạo một số điểm chuẩn kiểm tra 5 phương thức khác nhau trên một mảng chỉ có số ngẫu nhiên với 100000 mục .

Năm 2019, kết quả cho thấy vòng lặp tiêu chuẩn (mà BTW không có giới hạn kích thước) là nhanh nhất ở mọi nơi. applyvà lan truyền đến rất gần sau đó, sau đó là giải pháp lai của MDN sau đó reducelà chậm nhất.

Hầu như tất cả các bài kiểm tra đều cho kết quả như nhau, ngoại trừ một bài kiểm tra có kết quả chậm nhất.

Nếu bạn đẩy mạnh mảng của mình để có 1 triệu mục, mọi thứ bắt đầu bị phá vỡ và bạn bị bỏ lại với vòng lặp tiêu chuẩn như một giải pháp nhanh và reducechậm hơn.

Điểm chuẩn của JSPerf

jsperf.com kết quả điểm chuẩn cho các giải pháp khác nhau để tìm mục tối thiểu / tối đa của một mảng

Điểm chuẩn của JSBen

jsben.com kết quả điểm chuẩn cho các giải pháp khác nhau để tìm mục tối thiểu / tối đa của một mảng

Điểm chuẩn của JSBench.me

jsbench.me kết quả điểm chuẩn cho các giải pháp khác nhau để tìm mục tối thiểu / tối đa của một mảng

Mã nguồn chuẩn


Nếu bạn đang sử dụng bản thảo, toán tử trải rộng như được hiển thị sẽ được biên dịch để Math.max.apply(Math, arr)tương thích 'tối đa'.
Simon_Weaver

1
Cũng từ MDN: "cả lan truyền (...)applysẽ thất bại hoặc trả về kết quả sai nếu mảng có quá nhiều phần tử [...] Giải pháp rút gọn không có vấn đề này" Thử nghiệm Chrome, FF, Edge và IE11 có vẻ như đó là ok cho một mảng có giá trị lên tới 100k. (Đã thử nghiệm trên Win10 và các trình duyệt mới nhất: Chrome 110k, Firefox 300k, Edge 400k, IE11 150k).
oriadam

Đây là một phương thức rất chậm, nếu mảng sẽ có hàng ngàn phần tử thì sao?
Slava Fomin II

@SlavaFominII Tôi mở rộng câu trả lời để nó bao gồm các mảng với hàng ngàn phần tử.
totymedli

68

Nếu bạn hoang tưởng như tôi về việc sử dụng Math.max.apply(có thể gây ra lỗi khi được cung cấp các mảng lớn theo MDN ), hãy thử điều này:

function arrayMax(array) {
  return array.reduce(function(a, b) {
    return Math.max(a, b);
  });
}

function arrayMin(array) {
  return array.reduce(function(a, b) {
    return Math.min(a, b);
  });
}

Hoặc, trong ES6:

function arrayMax(array) {
  return array.reduce((a, b) => Math.max(a, b));
}

function arrayMin(array) {
  return array.reduce((a, b) => Math.min(a, b));
}

Rất tiếc, các hàm ẩn danh là không cần thiết (thay vì sử dụng Math.max.bind(Math)reducekhông chỉ truyền abchức năng của nó, mà còn ilà một tham chiếu đến chính mảng đó, vì vậy chúng tôi phải đảm bảo chúng tôi cũng không cố gắng gọi maxchúng.


Ví dụ ES6 của bạn, có bất kỳ lý do tại sao không chỉ trở lại Math.max(...array)?
Wojciech Bednarski

@WojciechBednarski trang này dường như đề xuất rằng việc sử dụng toán tử trải rộng cũng giống như truyền một mảng tới apply, và do đó có cùng nhược điểm (giới hạn đối số tối đa).
Daniel Buckmaster

Cám ơn vì cái này. Chỉ cần bạn có thể sửa khung bị thiếu sau khi giảm:function arrayMax(array) { return array.reduce(function(a, b) { return Math.max(a, b); }); // <--------- missing ) }
Arkowsky

1
@DanielDietrich Tôi đoán làm tương đương, gọi Math.min()không có giá trị, trả về Infinity, vì vậy các hàm này có thể sử dụng reduce(..., Infinity)để khớp với hành vi đó. Tôi thích nó ném một ngoại lệ mặc dù (như hiện tại), bởi vì lấy tối thiểu của một mảng trống dường như là một lỗi.
Daniel Buckmaster

1
cho đến nay giảm là chậm nhất.
Tiếng Pháp là

40

.apply thường được sử dụng khi có ý định gọi hàm matrixdic với danh sách các giá trị đối số, vd

Các Math.max([value1[,value2, ...]])hàm trả về lớn nhất trong số zero hoặc nhiều số.

Math.max(10, 20); // 20
Math.max(-10, -20); // -10
Math.max(-10, 20); // 20

Các Math.max() phương pháp không cho phép bạn để vượt qua trong một mảng. Nếu bạn có một danh sách các giá trị mà bạn cần lấy giá trị lớn nhất, thông thường bạn sẽ gọi hàm này bằng Function.prototype.apply () , vd

Math.max.apply(null, [10, 20]); // 20
Math.max.apply(null, [-10, -20]); // -10
Math.max.apply(null, [-10, 20]); // 20

Tuy nhiên, như là ECMAScript 6, bạn có thể sử dụng toán tử trải rộng :

Toán tử trải rộng cho phép một biểu thức được mở rộng ở những nơi có nhiều đối số (đối với các lệnh gọi hàm) hoặc nhiều phần tử (đối với các mảng bằng chữ) được mong đợi.

Sử dụng toán tử trải rộng, ở trên có thể được viết lại như sau:

Math.max(...[10, 20]); // 20
Math.max(...[-10, -20]); // -10
Math.max(...[-10, 20]); // 20

Khi gọi một hàm bằng toán tử matrixdic, bạn thậm chí có thể thêm các giá trị bổ sung, vd

Math.max(...[10, 20], 50); // 50
Math.max(...[-10, -20], 50); // 50

Tặng kem:

Điều hành lây lan cho phép bạn sử dụng cú pháp theo nghĩa đen mảng để tạo mảng mới trong tình huống mà trong ES5 bạn sẽ cần phải rơi trở lại mã bắt buộc, sử dụng kết hợp push, splicevv

let foo = ['b', 'c'];
let bar = ['a', ...foo, 'd', 'e']; // ['a', 'b', 'c', 'd', 'e']

1
Ví dụ cuối cùng của bạn trong phần thưởng sẽ được viết concatbởi hầu hết các lập trình viên bởi vì nó cho phép bạn duy trì một kiểu dòng duy nhất.
Cody Allan Taylor

31

Hai cách ngắn hơn và dễ dàng:

let arr = [2, 6, 1, 0]

Cách 1 :

let max = Math.max.apply(null, arr)

Cách 2 :

let max = arr.reduce(function(a, b) {
    return Math.max(a, b);
});

Xem ra nếu mảng trống - bạn sẽ nhận được vô cực âm có thể không phải là những gì bạn muốn. Nếu bạn muốn nhận, 0bạn có thể sử dụng [0].concat(arr)hoặc với cú pháp lây lan [0, ...arr](thay cho 'mảng')
Simon_Weaver

Có cách nào để loại trừ các giá trị null trong Cách 1 không?
bonbon.langes

22

Bạn làm điều đó bằng cách mở rộng kiểu Array:

Array.max = function( array ){
    return Math.max.apply( Math, array );
};
Array.min = function( array ){
    return Math.min.apply( Math, array );
}; 

Được tăng cường từ đây (bởi John Resig)


20

Một giải pháp đơn giản để tìm giá trị tối thiểu trên một Arrayphần tử là sử dụng Arrayhàm nguyên mẫu reduce:

A = [4,3,-9,-2,2,1];
A.reduce((min, val) => val < min ? val : min, A[0]); // returns -9

hoặc sử dụng hàm Math.Min () tích hợp của JavaScript (cảm ơn @Tenflex):

A.reduce((min,val) => Math.min(min,val), A[0]);

Cái này đặt minthành A[0], và sau đó kiểm tra A[1]...A[n]xem nó có hoàn toàn nhỏ hơn hiện tại không min. Nếu A[i] < minsau đó minđược cập nhật lên A[i]. Khi tất cả các phần tử mảng đã được xử lý, minkết quả sẽ được trả về.

EDIT : Bao gồm vị trí của giá trị tối thiểu:

A = [4,3,-9,-2,2,1];
A.reduce((min, val) => val < min._min ? {_min: val, _idx: min._curr, _curr: min._curr + 1} : {_min: min._min, _idx: min._idx, _curr: min._curr + 1}, {_min: A[0], _idx: 0, _curr: 0}); // returns { _min: -9, _idx: 2, _curr: 6 }

3
A.reduce ((phút, val) => Math.min (phút, val), A [0]); thậm chí ngắn hơn
Tenflex

Là một câu hỏi thưởng, làm thế nào để không chỉ mingiá trị được trả về mà cả vị trí của nó trong Mảng?
stevek

@meshfields - Tôi đã cập nhật câu trả lời.
Nicolas Lykke Iversen

15

Những người khác đã đưa ra một số giải pháp trong đó họ tăng cường Array.prototype. Tất cả những gì tôi muốn trong câu trả lời này là làm rõ liệu nó nên Math.min.apply( Math, array )hay Math.min.apply( null, array ). Vì vậy, bối cảnh nên được sử dụng, Mathhoặc null?

Khi chuyển nulldưới dạng bối cảnh sang applythì bối cảnh sẽ mặc định cho đối tượng toàn cục ( windowđối tượng trong trường hợp trình duyệt). Vượt qua Mathđối tượng làm bối cảnh sẽ là giải pháp chính xác, nhưng nó cũng không bị tổn thương khi vượt qua null. Đây là một ví dụ khi nullcó thể gây rắc rối, khi trang trí Math.maxchức năng:

// decorate Math.max
(function (oldMax) {
    Math.max = function () {
        this.foo(); // call Math.foo, or at least that's what we want

        return oldMax.apply(this, arguments);
    };
})(Math.max);

Math.foo = function () {
    print("foo");
};

Array.prototype.max = function() {
  return Math.max.apply(null, this); // <-- passing null as the context
};

var max = [1, 2, 3].max();

print(max);

Ở trên sẽ ném một ngoại lệ vì this.foosẽ được đánh giá là window.foo, đó là undefined. Nếu chúng ta thay thế nullvới Math, mọi thứ sẽ làm việc như mong đợi và chuỗi "foo" sẽ được in ra màn hình (Tôi đã thử nghiệm này sử dụng Mozilla Rhino ).

Bạn có thể khá nhiều giả định rằng không ai đã trang trí Math.maxnhư vậy, vượt qua nullsẽ làm việc mà không có vấn đề.


2
Điểm lấy. Tuy nhiên tại sao ai đó sẽ trang trí Foo.staticMethodvà tham khảo this? Đó sẽ không phải là một sai lầm trong thiết kế của trang trí? (tất nhiên trừ khi họ muốn tham chiếu phạm vi toàn cầu và muốn độc lập với công cụ JavaScript đang được sử dụng, ví dụ Rhino).
Roatin Marth

1
Thông số kỹ thuật rõ ràng về chức năng được chỉ định nào sẽ tham chiếu đến " giá trị này " (thực sự, cụm từ đó xuất hiện 125 lần trong đặc tả). Math.max, thực hiện trên mỗi spec, không sử dụng this. Nếu ai đó ghi đè lên Math.maxnhư vậy nó sử dụng this, thì họ đã làm cho hành vi của nó vi phạm thông số kỹ thuật và bạn nên ném các vật sắc nhọn vào chúng. Bạn không nên mã hóa xung quanh khả năng đó nhiều hơn bạn sẽ mã hóa xung quanh khả năng ai đó đã trao đổi Math.maxMath.mincho lulz.
Mark Amery

15

Một cách nữa để làm điều đó:

var arrayMax = Function.prototype.apply.bind(Math.max, null);

Sử dụng:

var max = arrayMax([2, 5, 1]);

Ai đó có thể giải thích làm thế nào điều này hoạt động? Điều này là khá dope. Sự hiểu biết của tôi có đúng không: ArrayMax là một hàm và chúng ta liên kết một cái gì đó với một thuộc tính của nguyên mẫu của nó? Ứng dụng này là gì và mọi nguyên mẫu đều có nó?
Sam


14

Các phương thức thay thế


Các phương thức Math.minMath.maxcả hai đều là các hoạt động đệ quy được thêm vào ngăn xếp cuộc gọi của công cụ JS và rất có thể là sự cố đối với một mảng chứa số lượng lớn các mục
(hơn ~ 10⁷ mục, tùy thuộc vào trình duyệt của người dùng).

Math.max (... Mảng (1000000) .keys ());

Uncaught RangeError: Vượt quá kích thước ngăn xếp cuộc gọi tối đa

Thay vào đó, sử dụng một cái gì đó như vậy:

arr.reduce((max, val) => max > val ? max : val, arr[0])

Hoặc với thời gian chạy tốt hơn:

function maxValue(arr) {
  let max = arr[0];

  for (let val of arr) {
    if (val > max) {
      max = val;
    }
  }
  return max;
}

Hoặc để có được cả Min và Max:

function getMinMax(arr) {
  return arr.reduce(({min, max}, v) => ({
    min: min < v ? min : v,
    max: max > v ? max : v,
  }), { min: arr[0], max: arr[0] });
}

Hoặc với thời gian chạy tốt hơn *:

function getMinMax(arr) {
  let min = arr[0];
  let max = arr[0];
  let i = arr.length;

  while (i--) {
    min = arr[i] < min ? arr[i] : min;
    max = arr[i] > max ? arr[i] : max;
  }
  return { min, max };
}

* Đã thử nghiệm với 1.000.000 mục:
Chỉ để tham khảo, thời gian chạy chức năng thứ nhất (trên máy của tôi) là 15,84ms so với chức năng thứ 2 chỉ với 4,32ms.


13

Điều này có thể phù hợp với mục đích của bạn.

Array.prototype.min = function(comparer) {

    if (this.length === 0) return null;
    if (this.length === 1) return this[0];

    comparer = (comparer || Math.min);

    var v = this[0];
    for (var i = 1; i < this.length; i++) {
        v = comparer(this[i], v);    
    }

    return v;
}

Array.prototype.max = function(comparer) {

    if (this.length === 0) return null;
    if (this.length === 1) return this[0];

    comparer = (comparer || Math.max);

    var v = this[0];
    for (var i = 1; i < this.length; i++) {
        v = comparer(this[i], v);    
    }

    return v;
}

bạn nên khởi tạo v của mình với 'this [0]' trong trường hợp không có số nào nhỏ hơn 0
jasonmw

Được comparercho là được gọi trong một số phạm vi cụ thể? Bởi vì nó là tài liệu tham khảo this[index]đó là undefinedmọi lúc.
Roatin Marth

Đã sửa, tôi luôn quên phạm vi cấp chức năng.
ChaosPandion

Ôi, bây giờ @Iovy G. Stan sẽ phê bình bạn vì lập luận "bối cảnh sai" giống như tôi đã làm, vì trình so sánh mặc định của bạn ( Math.xxx) sẽ chạy trong phạm vi toàn cầu ...
Roatin Marth

Điều đó có thể đúng, nhưng chữ ký hàm mới không yêu cầu phạm vi vì phải lấy 2 đối tượng cần so sánh.
ChaosPandion


12

Tôi ngạc nhiên không phải là một chức năng giảm.

var arr = [1, 10, 5, 11, 2]

var b = arr.reduce(function(previous,current){ 
                      return previous > current ? previous:current
                   });

b => 11
arr => [1, 10, 5, 11, 2]

Hãy nhận biết: giảm () được hỗ trợ từ IE9, xem developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/...
Paul Gobée

1
Tôi dường như không thể sử dụng điều này trong phiên bản hiện tại của Chromium.
PJSCopeland

9

Đối với mảng lớn (~ 10⁷ phần tử) Math.minMath.max tạo ra RangeError (vượt quá kích thước ngăn xếp cuộc gọi tối đa) trong node.js.

Đối với mảng lớn, giải pháp nhanh & bẩn là:

Array.prototype.min = function() {
    var r = this[0];
    this.forEach(function(v,i,a){if (v<r) r=v;});
    return r;
};

8

Tôi có cùng một vấn đề, tôi cần phải đạt được các giá trị tối thiểu và tối đa của một mảng và, thật ngạc nhiên, không có các hàm dựng sẵn cho các mảng. Sau khi đọc rất nhiều, tôi quyết định tự mình thử nghiệm các giải pháp "top 3":

  1. giải pháp riêng biệt: một vòng lặp FOR để kiểm tra mọi phần tử của mảng so với giá trị tối đa và / hoặc tối thiểu hiện tại;
  2. Giải pháp ÁP DỤNG: gửi mảng đến các hàm nội bộ Math.max và / hoặc Math.min bằng cách sử dụng áp dụng (null, mảng);
  3. Giải pháp GIẢM: đệ quy kiểm tra đối với mọi phần tử của mảng bằng cách sử dụng hàm giảm (hàm).

Mã kiểm tra là đây:

function GetMaxDISCRETE(A)
{   var MaxX=A[0];

    for (var X=0;X<A.length;X++)
        if (MaxX<A[X])
            MaxX=A[X];

    return MaxX;
}

function GetMaxAPPLY(A)
{   return Math.max.apply(null,A);
}

function GetMaxREDUCE(A)
{   return A.reduce(function(p,c)
    {   return p>c?p:c;
    });
}

Mảng A chứa đầy 100.000 số nguyên ngẫu nhiên, mỗi hàm được thực hiện 10.000 lần trên Mozilla Firefox 28.0 trên máy tính để bàn Pentium 4 2.99GHz intel với Windows Vista. Thời gian tính bằng giây, được lấy bởi hàm Performance.now (). Kết quả là như vậy, với 3 chữ số phân số và độ lệch chuẩn:

  1. Giải pháp rời rạc: mean = 0.161s, sd = 0.078
  2. Giải pháp ÁP DỤNG: mean = 3.571s, sd = 0.487
  3. Giải pháp GIẢM: trung bình = 0,350s, sd = 0,044

Giải pháp GIẢM GIÁ chậm hơn 117% so với giải pháp rời rạc. Giải pháp ỨNG DỤNG kém hơn, chậm hơn 2.118% so với giải pháp rời rạc. Ngoài ra, như Peter quan sát, nó không hoạt động cho các mảng lớn (khoảng hơn 1.000.000 phần tử).

Ngoài ra, để hoàn thành các bài kiểm tra, tôi đã kiểm tra mã rời rạc mở rộng này:

var MaxX=A[0],MinX=A[0];

for (var X=0;X<A.length;X++)
{   if (MaxX<A[X])
        MaxX=A[X];
    if (MinX>A[X])
        MinX=A[X];
}

Thời gian: mean = 0,218s, sd = 0,094

Vì vậy, nó chậm hơn 35% so với giải pháp rời rạc đơn giản, nhưng nó lấy cả giá trị tối đa và tối thiểu cùng một lúc (bất kỳ giải pháp nào khác sẽ mất ít nhất hai lần để lấy chúng). Khi OP cần cả hai giá trị, giải pháp rời rạc sẽ là lựa chọn tốt nhất (thậm chí là hai hàm riêng biệt, một để tính tối đa và một để tính tối thiểu, chúng sẽ vượt trội hơn giải pháp tốt nhất thứ hai, giải pháp GIẢM GIÁ).


8

Bạn có thể sử dụng chức năng sau ở bất cứ đâu trong dự án của bạn:

function getMin(array){
    return Math.min.apply(Math,array);
}

function getMax(array){
    return Math.max.apply(Math,array);
}

Và sau đó bạn có thể gọi các hàm truyền qua mảng:

var myArray = [1,2,3,4,5,6,7];
var maximo = getMax(myArray); //return the highest number

8

Đoạn mã sau hoạt động với tôi:

var valueList = [10,4,17,9,3];
var maxValue = valueList.reduce(function(a, b) { return Math.max(a, b); });
var minValue = valueList.reduce(function(a, b) { return Math.min(a, b); });

7

Lặp lại, theo dõi khi bạn đi.

var min = null;
var max = null;
for (var i = 0, len = arr.length; i < len; ++i)
{
    var elem = arr[i];
    if (min === null || min > elem) min = elem;
    if (max === null || max < elem) max = elem;
}
alert( "min = " + min + ", max = " + max );

Điều này sẽ để lại min / max null nếu không có phần tử nào trong mảng. Sẽ đặt min và max trong một lượt nếu mảng có bất kỳ phần tử nào.

Bạn cũng có thể mở rộng Array bằng một rangephương thức sử dụng ở trên để cho phép tái sử dụng và cải thiện khả năng đọc. Xem một fiddle làm việc tại http://jsfiddle.net/9C9fU/

Array.prototype.range = function() {

    var min = null,
        max = null,
        i, len;

    for (i = 0, len = this.length; i < len; ++i)
    {
        var elem = this[i];
        if (min === null || min > elem) min = elem;
        if (max === null || max < elem) max = elem;
    }

    return { min: min, max: max }
};

Được dùng như

var arr = [3, 9, 22, -7, 44, 18, 7, 9, 15];

var range = arr.range();

console.log(range.min);
console.log(range.max);

@JordanDillonChapian Tôi đồng ý, nhưng việc mở rộng rangechức năng này thành một chức năng sẽ là cách tốt nhất để có được cả min và max cùng một lúc IMO - như tôi đã thực hiện với một bản cập nhật cho câu trả lời của mình.
tvanfosson

6

Tôi nghĩ tôi muốn chia sẻ giải pháp đơn giản và dễ hiểu của mình.

Đối với phút:

var arr = [3, 4, 12, 1, 0, 5];
var min = arr[0];
for (var k = 1; k < arr.length; k++) {
  if (arr[k] < min) {
    min = arr[k];
  }
}
console.log("Min is: " + min);

Và tối đa:

var arr = [3, 4, 12, 1, 0, 5];
var max = arr[0];
for (var k = 1; k < arr.length; k++) {
  if (arr[k] > max) {
    max = arr[k];
  }
}
console.log("Max is: " + max);



Cảm ơn. Tôi đã thay đổi câu trả lời của tôi.
Iovy Necula

Lặp lại vẫn sai (truy cập các thuộc tính không tồn tại).
Bergi

Điều gì là sai, tôi không thấy bất cứ điều gì sai. Bạn có thể đưa ra một ví dụ xin vui lòng?
Iovy Necula

1
Sửa đổi cho phù hợp bây giờ. Hy vọng tôi hiểu bạn chính xác.
Iovy Necula

6

Ngoài việc sử dụng hàm toán học max và min, một hàm khác sẽ sử dụng là hàm dựng sẵn của sort (): ở đây chúng ta đi

const nums = [12, 67, 58, 30].sort((x, y) => 
x -  y)
let max = nums[0]
let min = nums[nums.length -1]

5

Những thứ đơn giản, thực sự.

var arr = [10,20,30,40];
arr.max = function() { return  Math.max.apply(Math, this); }; //attach max funct
arr.min = function() { return  Math.min.apply(Math, this); }; //attach min funct

alert("min: " + arr.min() + " max: " + arr.max());

5

Đây là một cách để có được giá trị tối đa từ một mảng các đối tượng. Tạo một bản sao (với lát), sau đó sắp xếp bản sao theo thứ tự giảm dần và lấy mục đầu tiên.

var myArray = [
    {"ID": 1, "Cost": 200},
    {"ID": 2, "Cost": 1000},
    {"ID": 3, "Cost": 50},
    {"ID": 4, "Cost": 500}
]

maxsort = myArray.slice(0).sort(function(a, b) { return b.ID - a.ID })[0].ID; 

5

Sử dụng Math.max()hoặcMath.min()

Math.max(10, 20);   //  20
Math.min(-10, -20); // -20

Hàm sau sử dụng Function.prototype.apply()để tìm phần tử tối đa trong một mảng số. getMaxOfArray([1, 2, 3])tương đương với Math.max(1, 2, 3), nhưng bạn có thể sử dụng getMaxOfArray()trên các mảng được xây dựng theo chương trình với mọi kích thước.

function getMaxOfArray(numArray) {
  return Math.max.apply(null, numArray);
}

Hoặc với toán tử trải rộng mới, việc lấy tối đa của một mảng trở nên dễ dàng hơn rất nhiều.

var arr = [1, 2, 3];
var max = Math.max(...arr); // 3
var min = Math.min(...arr); // 1

4

Giải pháp của ChaosPandion hoạt động nếu bạn đang sử dụng protoype. Nếu không, hãy xem xét điều này:

Array.max = function( array ){
    return Math.max.apply( Math, array );
};

Array.min = function( array ){
    return Math.min.apply( Math, array );
};

Ở trên sẽ trả về NaN nếu một giá trị mảng không phải là số nguyên vì vậy bạn nên xây dựng một số chức năng để tránh điều đó. Nếu không điều này sẽ làm việc.


jeerose, tại sao bạn có (Toán học, cái này) như là nông nghiệp khi Roatin Marth chỉ có (null, cái này)?
HankH

@HankH: xem phản hồi của tôi về bình luận của bạn trong một bình luận cho câu trả lời của riêng tôi.
Roatin Marth

1
Tôi không hiểu ý của bạn là "Giải pháp của ChaosPandion hoạt động nếu bạn đang sử dụng protoype". Giải pháp của bạn khác nhau như thế nào, ngoại trừ bạn đang sử dụng Mathđối tượng làm bối cảnh?
Ionuț G. Stan

Xin lỗi, ý tôi là nếu bạn mở rộng nguyên mẫu thì bạn sẽ làm việc. Lời xin lỗi.
jay

Vì vậy, cái nào tốt hơn, jeerose hay ChaosPandion?
HankH

3

Nếu bạn sử dụng thư viện sugar.js , bạn có thể viết Array.min ()Array.max () như bạn đề xuất. Bạn cũng có thể nhận các giá trị tối thiểu và tối đa từ các mảng không phải là số.

tối thiểu (bản đồ, tất cả = sai) Trả về phần tử trong mảng có giá trị thấp nhất. ánh xạ có thể là một hàm ánh xạ giá trị cần kiểm tra hoặc một chuỗi đóng vai trò là một phím tắt. Nếu tất cả là đúng, sẽ trả về tất cả các giá trị tối thiểu trong một mảng.

max (map, all = false) Trả về phần tử trong mảng có giá trị lớn nhất. ánh xạ có thể là một hàm ánh xạ giá trị cần kiểm tra hoặc một chuỗi đóng vai trò là một phím tắt. Nếu tất cả là đúng, sẽ trả về tất cả các giá trị tối đa trong một mảng.

Ví dụ:

[1,2,3].min() == 1
['fee','fo','fum'].min('length') == "fo"
['fee','fo','fum'].min('length', true) == ["fo"]
['fee','fo','fum'].min(function(n) { return n.length; }); == "fo"
[{a:3,a:2}].min(function(n) { return n['a']; }) == {"a":2}
['fee','fo','fum'].max('length', true) == ["fee","fum"]

Các thư viện như Lo-Dashunderscore.js cũng cung cấp các hàm tối thiểu và tối đa mạnh mẽ tương tự:

Ví dụ từ Lo-Dash:

_.max([4, 2, 8, 6]) == 8
var characters = [
  { 'name': 'barney', 'age': 36 },
  { 'name': 'fred',   'age': 40 }
];
_.max(characters, function(chr) { return chr.age; }) == { 'name': 'fred', 'age': 40 }

3
let arr = [2,5,3,5,6,7,1];

let max = Math.max(...arr); // 7
let min = Math.min(...arr); // 1

2
Giải pháp này đã được cung cấp bởi nhiều người trả lời khác cho câu hỏi này. Câu trả lời của bạn thêm gì?
Nick

3

Thử

let max= a=> a.reduce((m,x)=> m>x ? m:x);
let min= a=> a.reduce((m,x)=> m<x ? m:x);

Đối với Math.min / max (+ áp dụng), chúng tôi gặp lỗi:

Vượt quá kích thước ngăn xếp cuộc gọi tối đa (Chrome 74.0.3729.131)

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.