回答:
代わりにMath.max
/ を使用するように組み込みのArrayオブジェクトを拡張するのはどうですか?Math.min
Array.prototype.max = function() {
return Math.max.apply(null, this);
};
Array.prototype.min = function() {
return Math.min.apply(null, this);
};
こちらがJSFiddleです。
ビルトインを増強することは、他のライブラリ(一部参照)との衝突を引き起こす可能性がありますので、あなただけでより快適かもしれapply
「INGのMath.xxx()
直接配列へ:
var min = Math.min.apply(null, arr),
max = Math.max.apply(null, arr);
または、ブラウザーがECMAScript 6をサポートしていると仮定すると、メソッドと同様に機能するスプレッド演算子を使用できますapply
。
var min = Math.min( ...arr ),
max = Math.max( ...arr );
null
またはMath
または{}
または何にapply()
かcall()
な結果とは関係ありません。内部でMath.max
参照することも、参照することもできませんthis
。
Math.max.apply(null, $.makeArray(array));
.max
または.min
メソッドを提供する可能性についてもです。完全に現実的なシナリオ:この答えを使用します。2016年に、ES7またはES8スペックArray.max
とArray.min
。このバージョンとは異なり、文字列で動作します。あなたの将来の同僚は、文書化されたネイティブ.max()
メソッドを使用して、アルファベット順で最新の文字列を配列で取得しようとしますが、不思議なことにを取得しNaN
ます。数時間後、彼女はこのコードを見つけ、を実行しgit blame
、あなたの名前を呪います。
var max_of_array = Math.max.apply(Math, array);
詳細については、http://aaroncrane.co.uk/2008/11/javascript_max_api/を参照して ください。
Math.max.apply(Math, array)
とはMath.max.apply(null, array)
?ブログには「...にmax
属するものについても、冗長にもう一度言う必要がある」とありますMath
が、そうする必要はないようです(最初の引数をapply
asに設定することによりnull
)。
Math.max(a,b)
に呼び出すとMath
、this
値として渡されるため、で呼び出すときに同じようにすると意味がある場合がありapply
ます。ただしMath.max
、this
値は使用しないため、任意の値を渡すことができます。
大きな配列(〜10⁷要素)の場合Math.min
、Math.max
両方ともNode.jsで次のエラーを生成します。
RangeError:呼び出しスタックの最大サイズを超えました
より堅牢なソリューションは、すべての要素を呼び出しスタックに追加するのではなく、配列を渡すことです。
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 );
});
}
速度が気になる場合は、次のコードの方Math.max.apply
が私のコンピューターにある場合よりも3倍高速です。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;
};
配列に数値ではなく文字列が含まれている場合は、それらを数値に強制変換する必要もあります。以下のコードはそれを行いますが、私のマシンではコードを約10倍遅くします。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;
};
min
とmax
最後の要素へと1回の反復を減らす(while(--len)
);)
very different results
あなたは)この5年後でした
reduce
ソリューションは最も遅いです。数百万の要素を持つ配列を扱う場合でも、標準のforループを使用することをお勧めします。詳細については私の答えを参照してください。
If no arguments are given, the result is -∞.
// 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];
}
}
の公式MDNドキュメントはMath.max()
すでにこの問題をカバーしています:
次の関数は、Function.prototype.apply()を使用して、数値配列の最大要素を検索します。
getMaxOfArray([1, 2, 3])
はと同等Math.max(1, 2, 3)
ですがgetMaxOfArray()
、プログラムで作成された任意のサイズの配列で使用できます。function getMaxOfArray(numArray) { return Math.max.apply(null, numArray); }
または、新しいスプレッド演算子を使用すると、配列の最大値を取得するのがはるかに簡単になります。
var arr = [1, 2, 3]; var max = Math.max(...arr);
MDNによると、展開apply
ソリューションには 65536の制限があり、これは引数の最大数の制限によるものです。
ただし、注意してください。applythis wayを使用すると、JavaScriptエンジンの引数の長さ制限を超えるリスクがあります。引数が多すぎる(数万を超えると考える)関数を適用した場合の結果は、エンジンによって異なります(JavaScriptCoreには65536の引数がハードコードされています)。動作)は指定されていません。一部のエンジンは例外をスローします。さらに悪質なことに、適用された関数に実際に渡される引数の数を制限する人もいます。この後者のケースを説明すると、そのようなエンジンに4つの引数の制限があった場合(実際の制限はもちろん大幅に高くなります)、上記の例に適用するために引数5、6、2、3が渡されたかのようになります。完全な配列ではなく。
彼らは、他のソリューションと比較して実際に優れたパフォーマンスを持たないハイブリッドソリューションさえ提供します。詳細については、以下のパフォーマンステストを参照してください。
2019年の実際の制限は、コールスタックの最大サイズです。最新のChromiumベースのデスクトップブラウザーの場合、これは、最小値apply
または最大値またはスプレッドを検出する場合、実際には数値のみの配列の最大サイズが〜120000であることを意味します。これを超えると、スタックオーバーフローが発生し、次のエラーがスローされます。
RangeError:呼び出しスタックの最大サイズを超えました
以下のスクリプト(このブログ投稿に基づく)では、そのエラーをキャッチすることで、特定の環境の制限を計算できます。
警告!このスクリプトの実行には時間がかかり、システムのパフォーマンスによっては、ブラウザー/システムが遅くなったりクラッシュしたりする場合があります。
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;
}
}
EscapeNetscapeのコメントのテストに基づいて、100,000アイテムの乱数のみの配列で 5つの異なるメソッドをテストするいくつかのベンチマークを作成しました。
2019年の結果は、標準ループ(BTWにはサイズ制限がない)がどこでも最速であることを示しています。apply
そして、その直後に拡散が続き、その後、MDNのハイブリッドソリューションreduce
が最も遅くなります。
ほとんどすべてのテストで同じ結果が得られました。
配列を100万個のアイテムにステップアップすると、状況が崩れ始め、標準ループは高速なソリューションとreduce
低速なソリューションとして残されます。
Math.max.apply(Math, arr)
「最大」の互換性のためにコンパイルされます。
(...)
とapply
失敗したり、配列があまりにも多くの要素を持っている場合、誤った結果を返しますいずれかの[...]このような問題はありませんソリューションを減らす」のテストChromeを、FF、エッジとIE11はあると思われます100kまでの値の配列には問題ありません。(Win10および最新のブラウザーでテスト済み:Chrome 110k、Firefox 300k、Edge 400k、IE11 150k)。
私のように使用することに偏執的である場合Math.max.apply
(MDNに従って大きな配列を指定するとエラーが発生する可能性があります)、これを試してください:
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);
});
}
または、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));
}
無名関数は、残念ながら必要に応じて(代わりに使用しているMath.max.bind(Math)
ので、reduce
ただ合格しないa
と、b
その機能にするだけでなく、i
我々は呼び出すためにしようとしないことを確認する必要がありますので、配列自体への参照max
だけでなく、それらに。
Math.max(...array)
か?
apply
に渡すことと同じであるため、同じ欠点(最大引数制限)があることを示唆しているようです。
function arrayMax(array) { return array.reduce(function(a, b) { return Math.max(a, b); }); // <--------- missing ) }
Math.min()
ますInfinity
、値なしで呼び出すと、が返されるので、これらの関数はreduce(..., Infinity)
その動作に一致させるために使用できます。ただし、(現在のように)例外をスローすることをお勧めします。空の配列を最小限にするとエラーになる可能性があるためです。
.apply
引数値のリストを使用して可変個関数を呼び出すことが目的の場合によく使用されます。例:
このMath.max([value1[,value2, ...]])
関数は、ゼロまたはそれ以上の数値の最大値を返します。
Math.max(10, 20); // 20
Math.max(-10, -20); // -10
Math.max(-10, 20); // 20
このMath.max()
メソッドでは、配列を渡すことはできません。最大値を取得する必要がある値のリストがある場合、通常はFunction.prototype.apply()を使用してこの関数を呼び出します。たとえば、
Math.max.apply(null, [10, 20]); // 20
Math.max.apply(null, [-10, -20]); // -10
Math.max.apply(null, [-10, 20]); // 20
ただし、ECMAScript 6以降では、spread演算子を使用できます。
スプレッド演算子を使用すると、複数の引数(関数呼び出しの場合)または複数の要素(配列リテラルの場合)が予想される場所で式を展開できます。
スプレッド演算子を使用すると、上記のように書き直すことができます。
Math.max(...[10, 20]); // 20
Math.max(...[-10, -20]); // -10
Math.max(...[-10, 20]); // 20
可変個の演算子を使用して関数を呼び出すときは、さらに値を追加することもできます。
Math.max(...[10, 20], 50); // 50
Math.max(...[-10, -20], 50); // 50
ボーナス:
スプレッド演算子は、あなたはES5にあなたがの組み合わせを使用して、必要不可欠コードにフォールバックする必要があるだろう状況で新しいアレイを作成するには、配列リテラル構文を使用することを可能にするpush
、splice
など、
let foo = ['b', 'c'];
let bar = ['a', ...foo, 'd', 'e']; // ['a', 'b', 'c', 'd', 'e']
concat
単一の線スタイルを維持できるため、ほとんどのプログラマーが使用して記述します。
2つの方法は短くて簡単です。
let arr = [2, 6, 1, 0]
方法1:
let max = Math.max.apply(null, arr)
方法2:
let max = arr.reduce(function(a, b) {
return Math.max(a, b);
});
0
たい場合は[0].concat(arr)
、スプレッド構文[0, ...arr]
( 'arr'の代わりに)を使用できます
Array
要素の最小値を見つける簡単な解決策は、Array
プロトタイプ関数を使用することreduce
です:
A = [4,3,-9,-2,2,1];
A.reduce((min, val) => val < min ? val : min, A[0]); // returns -9
またはJavaScriptの組み込みMath.Min()関数を使用(@Tenflexに感謝):
A.reduce((min,val) => Math.min(min,val), A[0]);
これはに設定さmin
れA[0]
、A[1]...A[n]
現在の値よりも厳密に小さいかどうかを確認しmin
ます。場合はA[i] < min
、その後min
に更新されますA[i]
。すべての配列要素が処理されるmin
と、結果として返されます。
編集:最小値の位置を含める:
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 }
min
値を返すだけでなく、配列内での位置を返す方法はありますか?
他の人たちは、それらを増強するいくつかの解決策をすでに与えていArray.prototype
ます。私はこの答えに欲しいのは、それがどうあるべきかを明らかにすることですMath.min.apply( Math, array )
かMath.min.apply( null, array )
。だから何コンテキストを使用し、する必要がありますMath
かnull
?
にnull
コンテキストとして渡すとapply
、コンテキストはデフォルトでグローバルオブジェクト(window
ブラウザの場合はオブジェクト)になります。Math
オブジェクトをコンテキストとして渡すことは正しい解決策ですが、渡すことも害にはなりませんnull
。関数をnull
装飾するときに問題が発生する可能性がある場合の例を次に示しMath.max
ます。
// 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);
ため、上記の例外がスローされますthis.foo
ように評価されるwindow.foo
です、undefined
。で置き換えるnull
とMath
、期待どおりに動作し、文字列「foo」が画面に表示されます(これはMozilla Rhinoを使用してテストしました)。
だれもMath.max
そのように装飾していないとほぼ仮定できnull
ます。パスは問題なく機能します。
Foo.staticMethod
して参照するのthis
ですか?それはデコレータのデザインの間違いではないでしょうか?(もちろん、しない限り、彼らがして望むグローバルスコープを参照するように、としたい使用されているJavaScriptエンジンの独立性を維持するために、例えばサイ)。
Math.max
、仕様に従って実装され、は使用しませんthis
。誰かMath.max
がを使用するようにオーバーライドした場合this
、その動作は仕様に違反しているため、鋭いオブジェクトを投げる必要があります。その可能性をコーディングするのは、誰かが入れ替えた可能性Math.max
やMath.min
lulzをコーディングするのと同じです。
メソッドJSエンジンのコールスタックに追加されていることの両方の再帰的な操作であり、最も可能性の高いクラッシュのアイテムが多数含まれているアレイ用(〜10⁷項目以上に、ユーザーのブラウザに依存します)。Math.min
Math.max
Math.max(... Array(1000000).keys());
キャッチされないRangeError:呼び出しスタックの最大サイズを超えました
代わりに、次のようなものを使用します。
arr.reduce((max, val) => max > val ? max : val, arr[0])
または、より良いランタイムで:
function maxValue(arr) {
let max = arr[0];
for (let val of arr) {
if (val > max) {
max = val;
}
}
return 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] });
}
または、さらに優れたランタイム*:
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 };
}
* 1,000,000項目でテスト:
参考までに、(私のマシンでの)1番目の関数の実行時間は15.84ミリ秒でしたが、4.32ミリ秒で2番目の関数が実行されました。
これはあなたの目的に合うかもしれません。
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;
}
comparer
いくつかの特定のスコープで呼び出されることになって?それが参照されているためthis[index]
であるundefined
毎回。
Math.xxx
https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/Math/max
function getMaxOfArray(numArray) {
return Math.max.apply(null, numArray);
}
var arr = [100, 0, 50];
console.log(getMaxOfArray(arr))
これは私のために働いた。
リデュース機能について触れられていないことに驚いています。
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]
同じ問題がありました。配列の最小値と最大値を取得する必要があり、驚いたことに、配列の組み込み関数がありませんでした。たくさん読んだ後、「トップ3」のソリューションを自分でテストすることにしました。
テストコードはこれでした:
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;
});
}
配列Aは100,000個のランダムな整数で埋められ、各関数はWindows Vista搭載のIntel Pentium 4 2.99GHzデスクトップ上のMozilla Firefox 28.0で10,000回実行されました。時間は秒単位で、performance.now()関数によって取得されます。結果は次のとおりで、3つの小数桁と標準偏差が含まれています。
REDUCEソリューションは、個別ソリューションより117%遅くなりました。APPLYソリューションは、ディスクリートソリューションよりも劣っており、2,118%遅くなりました。その上、Peterが観察したように、それは大きな配列(約1,000,000要素を超える)では機能しません。
また、テストを完了するために、この拡張ディスクリートコードをテストしました。
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];
}
タイミング:平均= 0.218秒、sd = 0.094
したがって、単純な離散ソリューションより35%遅くなりますが、最大値と最小値の両方を一度に取得します(他のソリューションでは、取得に少なくとも2倍かかります)。OPが両方の値を必要とすると、個別のソリューションが最良の選択になります(最大値を計算するための関数と最小値を計算するための関数の2つの別々の関数としても、2番目に優れたREDUCEソリューションよりも優れています)。
次のコードは私のために働きます:
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); });
何度も繰り返しながら、進行状況を追跡します。
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 );
配列に要素がない場合、これは最小値/最大値をnullのままにします。配列に要素がある場合、1つのパスで最小値と最大値を設定します。
range
上記を使用する方法でArrayを拡張して、再利用を可能にし、読みやすさを向上させることもできます。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 }
};
使用されます
var arr = [3, 9, 22, -7, 44, 18, 7, 9, 15];
var range = arr.range();
console.log(range.min);
console.log(range.max);
range
、最小値と最大値の両方を同時にIMOに取得するための最良の方法である関数に拡張するのは簡単です。
シンプルでわかりやすい解決策を共有したいと思いました。
最小:
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);
そして最大のために:
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);
Math.max()
またはを使用するMath.min()
Math.max(10, 20); // 20
Math.min(-10, -20); // -20
次の関数はFunction.prototype.apply()
、数値配列の最大要素を見つけるために使用します。getMaxOfArray([1, 2, 3])
はと同等Math.max(1, 2, 3)
ですがgetMaxOfArray()
、プログラムで作成された任意のサイズの配列で使用できます。
function getMaxOfArray(numArray) {
return Math.max.apply(null, numArray);
}
または、新しいスプレッド演算子を使用すると、配列の最大値を取得するのがはるかに簡単になります。
var arr = [1, 2, 3];
var max = Math.max(...arr); // 3
var min = Math.min(...arr); // 1
ChaosPandionのソリューションは、プロトタイプを使用している場合に機能します。そうでない場合は、これを考慮してください:
Array.max = function( array ){
return Math.max.apply( Math, array );
};
Array.min = function( array ){
return Math.min.apply( Math, array );
};
上記は配列値が整数でない場合NaNを返すので、それを回避するためにいくつかの機能を構築する必要があります。それ以外の場合はこれでうまくいきます。
Math
オブジェクトをコンテキストとして使用していることを除いて、ソリューションはどのように異なりますか?
ライブラリsugar.jsを使用する場合は、arr.min()およびarr.max()を推奨どおりに記述できます。非数値配列から最小値と最大値を取得することもできます。
min(map、all = false)最小の値を持つ配列の要素を返します。mapは、チェックされる値をマッピングする関数、またはショートカットとして機能する文字列です。allがtrueの場合、配列内のすべての最小値を返します。
max(map、all = false)最大の値を持つ配列の要素を返します。mapは、チェックされる値をマッピングする関数、またはショートカットとして機能する文字列です。allがtrueの場合、配列内のすべての最大値を返します。
例:
[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"]
Lo-Dashやunderscore.jsなどのライブラリも、同様の強力なminおよびmax関数を提供します。
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 }
試す
let max= a=> a.reduce((m,x)=> m>x ? m:x);
let min= a=> a.reduce((m,x)=> m<x ? m:x);
Math.min / max(+ apply)の場合、エラーが発生します。
呼び出しスタックの最大サイズを超えました(Chrome 74.0.3729.131)
...
で)Math.max()
このように:Math.max(...[2, 5, 16, 1])
。MDNドキュメントからの私の回答を参照してください。