Cách hiệu quả nhất để tạo ra một mảng có độ dài bằng 0 tùy ý trong JavaScript là gì?
let i = 0; Array.from(Array(10), ()=>i++);
Cách hiệu quả nhất để tạo ra một mảng có độ dài bằng 0 tùy ý trong JavaScript là gì?
let i = 0; Array.from(Array(10), ()=>i++);
Câu trả lời:
ES6 giới thiệu Array.prototype.fill
. Nó có thể được sử dụng như thế này:
new Array(len).fill(0);
Không chắc nó có nhanh không, nhưng tôi thích nó vì nó ngắn và tự mô tả.
Nó vẫn chưa có trong IE ( kiểm tra tính tương thích ), nhưng có sẵn một polyfill .
new Array(len)
là đau đớn chậm. (arr = []).length = len; arr.fill(0);
là về giải pháp nhanh nhất tôi từng thấy ở bất cứ đâu ... hoặc ít nhất là bị trói
arr = Array(n)
và (arr = []).length = n
hành xử giống hệt nhau theo thông số kỹ thuật. Trong một số triển khai, người ta có thể nhanh hơn, nhưng tôi không nghĩ có sự khác biệt lớn.
(arr = []).length = 1000;
để arr = new Array(1000);
kiểm tra tốc độ trong cả Chrome và FF ... new
tốc độ rất chậm. Bây giờ, đối với độ dài mảng nhỏ hơn .. giả sử <50 hoặc có abouts ... thì new Array()
dường như hoạt động tốt hơn. Nhưng ..
arr.fill(0)
... mọi thứ đều thay đổi. Bây giờ, việc sử dụng new Array()
nhanh hơn trong hầu hết các trường hợp ngoại trừ khi bạn có kích thước mảng> 100000 ... Sau đó, bạn có thể bắt đầu thấy tốc độ tăng trở lại. Nhưng nếu bạn không thực sự phải điền trước nó bằng số không và có thể sử dụng các mảng trống tiêu chuẩn. Sau đó (arr = []).length = x
là điên nhanh trong các trường hợp thử nghiệm của tôi hầu hết thời gian.
new Array(5).forEach(val => console.log('hi'));
vs new Array(5).fill(undefined).forEach(val => console.log('hi'));
.
Mặc dù đây là một chủ đề cũ, tôi muốn thêm 2 xu của mình vào đó. Không chắc mức độ chậm / nhanh của nó, nhưng nó là một lớp lót nhanh. Đây là những gì tôi làm:
Nếu tôi muốn điền trước một số:
Array.apply(null, Array(5)).map(Number.prototype.valueOf,0);
// [0, 0, 0, 0, 0]
Nếu tôi muốn điền trước bằng một chuỗi:
Array.apply(null, Array(3)).map(String.prototype.valueOf,"hi")
// ["hi", "hi", "hi"]
Các câu trả lời khác đã đề xuất:
new Array(5+1).join('0').split('')
// ["0", "0", "0", "0", "0"]
nhưng nếu bạn muốn 0 (số) chứ không phải "0" (không trong chuỗi), bạn có thể làm:
new Array(5+1).join('0').split('').map(parseFloat)
// [0, 0, 0, 0, 0]
Array.apply(null, new Array(5)).map(...)
? Nguyên nhân đơn giản là làm (Mảng mới (5)). Map (...) sẽ không hoạt động như thông số kỹ thuật nói
new
) Khi bạn Array(5)
tạo một đối tượng giống như thế này: { length: 5, __proto__: Array.prototype }
- hãy thử console.dir( Array(5) )
. Chú ý rằng nó không có bất kỳ thuộc tính 0
, 1
, 2
, vv Tuy nhiên, khi bạn apply
rằng cho đến Array
constructor, nó giống như nói Array(undefined, undefined, undefined, undefined, undefined)
. Và bạn nhận được một đối tượng giống như thế { length: 5, 0: undefined, 1: undefined...}
. map
hoạt động trên các thuộc tính 0
, 1
vv đó là lý do tại sao ví dụ của bạn không hoạt động, nhưng khi bạn sử dụng apply
nó.
.apply
thực sự là những gì bạn muốn this
. Đối với những mục đích this
này, điều đó không thành vấn đề - chúng tôi chỉ thực sự quan tâm đến "tính năng" lan truyền tham số .apply
- vì vậy nó có thể là bất kỳ giá trị nào. Tôi thích null
vì nó rẻ, có lẽ bạn không muốn sử dụng {}
hoặc []
vì bạn đang bắt đầu một đối tượng mà không có lý do.
Đây là một cách khác để làm điều đó bằng ES6 mà chưa ai đề cập cho đến nay:
> Array.from(Array(3), () => 0)
< [0, 0, 0]
Nó hoạt động bằng cách thông qua một chức năng bản đồ như tham số thứ hai của Array.from
.
Trong ví dụ trên, tham số đầu tiên phân bổ một mảng gồm 3 vị trí chứa đầy giá trị undefined
và sau đó hàm lambda ánh xạ mỗi một trong số chúng thành giá trị 0
.
Mặc dù Array(len).fill(0)
ngắn hơn, nhưng nó không hoạt động nếu bạn cần điền vào mảng bằng cách thực hiện một số tính toán trước (tôi biết câu hỏi không yêu cầu, nhưng rất nhiều người cuối cùng tìm kiếm điều này) .
Chẳng hạn, nếu bạn cần một mảng có 10 số ngẫu nhiên:
> Array.from(Array(10), () => Math.floor(10 * Math.random()))
< [3, 6, 8, 1, 9, 3, 0, 6, 7, 1]
Nó ngắn gọn (và thanh lịch) hơn tương đương:
const numbers = Array(10);
for (let i = 0; i < numbers.length; i++) {
numbers[i] = Math.round(10 * Math.random());
}
Phương pháp này cũng có thể được sử dụng để tạo các chuỗi số bằng cách tận dụng tham số chỉ mục được cung cấp trong cuộc gọi lại:
> Array.from(Array(10), (d, i) => i)
< [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
repeat()
Vì câu trả lời này đang nhận được rất nhiều sự chú ý, tôi cũng muốn thể hiện thủ thuật tuyệt vời này. Mặc dù không hữu ích như câu trả lời chính của tôi, sẽ giới thiệu repeat()
phương thức String vẫn chưa được biết đến nhưng rất hữu ích . Đây là mẹo:
> "?".repeat(10).split("").map(() => Math.floor(10 * Math.random()))
< [5, 6, 3, 5, 0, 8, 2, 7, 4, 1]
Mát mẻ, huh? repeat()
là một phương pháp rất hữu ích để tạo ra một chuỗi là sự lặp lại của chuỗi ban đầu một số lần nhất định. Sau đó, split()
tạo một mảng cho chúng ta, sau đó map()
chuyển sang các giá trị chúng ta muốn. Chia nhỏ nó theo các bước:
> "?".repeat(10)
< "??????????"
> "?".repeat(10).split("")
< ["?", "?", "?", "?", "?", "?", "?", "?", "?", "?"]
> "?".repeat(10).split("").map(() => Math.floor(10 * Math.random()))
< [5, 6, 3, 5, 0, 8, 2, 7, 4, 1]
repeat
mánh khóe chắc chắn không muốn trong sản xuất, nhưng Array.from()
hoàn toàn ổn :-)
Giải pháp nhanh nhất
let a = new Array(n); for (let i=0; i<n; ++i) a[i] = 0;
Ngắn nhất (tiện dụng) dung dịch (3x chậm hơn cho mảng nhỏ, hơi chậm cho lớn (chậm nhất trên Firefox))
Array(n).fill(0)
Hôm nay 2020,06,09 Tôi thực hiện các thử nghiệm trên macOS High Sierra 10.13.6 trên các trình duyệt Chrome 83.0, Firefox 77.0 và Safari 13.1. Tôi kiểm tra các giải pháp được lựa chọn cho hai trường hợp thử nghiệm
new Array(n)+for
(N) là giải pháp nhanh nhất cho các mảng nhỏ và mảng lớn (trừ Chrome nhưng vẫn rất nhanh ở đó) và nó được đề xuất là giải pháp trình duyệt chéo nhanhnew Float32Array(n)
(I) trả về mảng không điển hình (ví dụ: bạn không thể gọipush(..)
vào nó) vì vậy tôi không so sánh kết quả của nó với các giải pháp khác - tuy nhiên giải pháp này là khoảng 10-20x nhanh hơn so với các giải pháp khác cho mảng lớn trên tất cả các trình duyệtfor
(L, M, N, O) nhanh chóng cho các mảng nhỏfill
(B, C) nhanh trên Chrome và Safari nhưng chậm nhất một cách đáng ngạc nhiên trên Firefox cho các mảng lớn. Chúng là trung bình nhanh cho các mảng nhỏArray.apply
(P) ném lỗi cho mảng lớn
Dưới đây mã trình bày các giải pháp được sử dụng trong các phép đo
Kết quả ví dụ cho Chrome
let a=[]; for(i=n;i--;) a.push(0);
- nhưng nó chậm hơn 4 lần so với fill(0)
- vì vậy tôi thậm chí sẽ không cập nhật phù thủy hình ảnh đó.
Phương pháp điền vào ES 6 đã được đề cập sẽ xử lý việc này một cách độc đáo. Hầu hết các trình duyệt máy tính để bàn hiện đại đã hỗ trợ các phương thức nguyên mẫu Array cần thiết cho đến ngày nay (Chromium, FF, Edge và Safari) [ 1 ]. Bạn có thể tra cứu chi tiết về MDN . Một ví dụ sử dụng đơn giản là
a = new Array(10).fill(0);
Với sự hỗ trợ của trình duyệt hiện tại, bạn nên thận trọng khi sử dụng điều này trừ khi bạn chắc chắn khán giả của mình sử dụng các trình duyệt Desktop hiện đại.
a = Array(10).fill(null).map(() => { return []; });
a = Array(10).fill(0).map( _ => [] );
Lưu ý thêm vào tháng 8 năm 2013, cập nhật tháng 2 năm 2015: Câu trả lời dưới đây từ năm 2009 liên quan đến loại chung của JavaScript Array
. Nó không liên quan đến các mảng được gõ mới hơn được xác định trong ES2015 [và hiện có sẵn trong nhiều trình duyệt], như thế Int32Array
và như vậy. Cũng lưu ý rằng ES2015 thêm một fill
phương thức cho cả Mảng và mảng được gõ , đây có thể là cách hiệu quả nhất để lấp đầy chúng ...
Ngoài ra, nó có thể tạo ra sự khác biệt lớn đối với một số cách triển khai cách bạn tạo mảng. Công cụ V8 của Chrome, đặc biệt, cố gắng sử dụng mảng bộ nhớ liền kề, hiệu quả cao nếu nó nghĩ rằng nó có thể, chỉ chuyển sang mảng dựa trên đối tượng khi cần thiết.
Với hầu hết các ngôn ngữ, nó sẽ được phân bổ trước, sau đó điền vào không, như thế này:
function newFilledArray(len, val) {
var rv = new Array(len);
while (--len >= 0) {
rv[len] = val;
}
return rv;
}
Nhưng , mảng JavaScript không thực sự là mảng , chúng là bản đồ khóa / giá trị giống như tất cả các đối tượng JavaScript khác, do đó, không có "phân bổ trước" để làm (đặt độ dài không phân bổ nhiều vị trí cần điền), cũng không Có lý do nào để tin rằng lợi ích của việc đếm ngược về không (điều này chỉ giúp cho việc so sánh trong vòng lặp nhanh) không vượt trội bằng cách thêm các khóa theo thứ tự ngược lại khi việc triển khai có thể tối ưu hóa việc xử lý các phím của chúng liên quan đến mảng trên lý thuyết nói chung bạn sẽ thực hiện chúng theo thứ tự.
Trên thực tế, Matthew Crumley đã chỉ ra rằng việc đếm ngược trên Firefox chậm hơn rõ rệt so với việc đếm ngược, kết quả tôi có thể xác nhận - đó là phần mảng của nó (lặp xuống 0 vẫn nhanh hơn so với lặp đến giới hạn trong một var). Rõ ràng việc thêm các phần tử vào mảng theo thứ tự ngược lại là một hoạt động chậm trên Firefox. Trên thực tế, kết quả thay đổi khá nhiều khi triển khai JavaScript (điều này không đáng ngạc nhiên lắm). Đây là một trang thử nghiệm nhanh và bẩn (bên dưới) để triển khai trình duyệt (rất bẩn, không mang lại hiệu quả trong các thử nghiệm, do đó cung cấp phản hồi tối thiểu và sẽ chạy theo giới hạn thời gian của tập lệnh). Tôi khuyên bạn nên làm mới giữa các bài kiểm tra; FF (ít nhất) làm chậm các bài kiểm tra lặp đi lặp lại nếu bạn không.
Phiên bản khá phức tạp sử dụng Array # concat nhanh hơn một init thẳng trên FF kể từ khoảng 1.000 đến 2.000 mảng phần tử. Tuy nhiên, trên công cụ V8 của Chrome, init thẳng sẽ thắng mỗi lần ...
Đây là trang thử nghiệm ( bản sao trực tiếp ):
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Zero Init Test Page</title>
<style type='text/css'>
body {
font-family: sans-serif;
}
#log p {
margin: 0;
padding: 0;
}
.error {
color: red;
}
.winner {
color: green;
font-weight: bold;
}
</style>
<script type='text/javascript' src='prototype-1.6.0.3.js'></script>
<script type='text/javascript'>
var testdefs = {
'downpre': {
total: 0,
desc: "Count down, pre-decrement",
func: makeWithCountDownPre
},
'downpost': {
total: 0,
desc: "Count down, post-decrement",
func: makeWithCountDownPost
},
'up': {
total: 0,
desc: "Count up (normal)",
func: makeWithCountUp
},
'downandup': {
total: 0,
desc: "Count down (for loop) and up (for filling)",
func: makeWithCountDownArrayUp
},
'concat': {
total: 0,
desc: "Concat",
func: makeWithConcat
}
};
document.observe('dom:loaded', function() {
var markup, defname;
markup = "";
for (defname in testdefs) {
markup +=
"<div><input type='checkbox' id='chk_" + defname + "' checked>" +
"<label for='chk_" + defname + "'>" + testdefs[defname].desc + "</label></div>";
}
$('checkboxes').update(markup);
$('btnTest').observe('click', btnTestClick);
});
function epoch() {
return (new Date()).getTime();
}
function btnTestClick() {
// Clear log
$('log').update('Testing...');
// Show running
$('btnTest').disabled = true;
// Run after a pause while the browser updates display
btnTestClickPart2.defer();
}
function btnTestClickPart2() {
try {
runTests();
}
catch (e) {
log("Exception: " + e);
}
// Re-enable the button; we don't yheidl
$('btnTest').disabled = false;
}
function runTests() {
var start, time, counter, length, defname, def, results, a, invalid, lowest, s;
// Get loops and length
s = $F('txtLoops');
runcount = parseInt(s);
if (isNaN(runcount) || runcount <= 0) {
log("Invalid loops value '" + s + "'");
return;
}
s = $F('txtLength');
length = parseInt(s);
if (isNaN(length) || length <= 0) {
log("Invalid length value '" + s + "'");
return;
}
// Clear log
$('log').update('');
// Do it
for (counter = 0; counter <= runcount; ++counter) {
for (defname in testdefs) {
def = testdefs[defname];
if ($('chk_' + defname).checked) {
start = epoch();
a = def.func(length);
time = epoch() - start;
if (counter == 0) {
// Don't count (warm up), but do check the algorithm works
invalid = validateResult(a, length);
if (invalid) {
log("<span class='error'>FAILURE</span> with def " + defname + ": " + invalid);
return;
}
}
else {
// Count this one
log("#" + counter + ": " + def.desc + ": " + time + "ms");
def.total += time;
}
}
}
}
for (defname in testdefs) {
def = testdefs[defname];
if ($('chk_' + defname).checked) {
def.avg = def.total / runcount;
if (typeof lowest != 'number' || lowest > def.avg) {
lowest = def.avg;
}
}
}
results =
"<p>Results:" +
"<br>Length: " + length +
"<br>Loops: " + runcount +
"</p>";
for (defname in testdefs) {
def = testdefs[defname];
if ($('chk_' + defname).checked) {
results += "<p" + (lowest == def.avg ? " class='winner'" : "") + ">" + def.desc + ", average time: " + def.avg + "ms</p>";
}
}
results += "<hr>";
$('log').insert({top: results});
}
function validateResult(a, length) {
var n;
if (a.length != length) {
return "Length is wrong";
}
for (n = length - 1; n >= 0; --n) {
if (a[n] != 0) {
return "Index " + n + " is not zero";
}
}
return undefined;
}
function makeWithCountDownPre(len) {
var a;
a = new Array(len);
while (--len >= 0) {
a[len] = 0;
}
return a;
}
function makeWithCountDownPost(len) {
var a;
a = new Array(len);
while (len-- > 0) {
a[len] = 0;
}
return a;
}
function makeWithCountUp(len) {
var a, i;
a = new Array(len);
for (i = 0; i < len; ++i) {
a[i] = 0;
}
return a;
}
function makeWithCountDownArrayUp(len) {
var a, i;
a = new Array(len);
i = 0;
while (--len >= 0) {
a[i++] = 0;
}
return a;
}
function makeWithConcat(len) {
var a, rem, currlen;
if (len == 0) {
return [];
}
a = [0];
currlen = 1;
while (currlen < len) {
rem = len - currlen;
if (rem < currlen) {
a = a.concat(a.slice(0, rem));
}
else {
a = a.concat(a);
}
currlen = a.length;
}
return a;
}
function log(msg) {
$('log').appendChild(new Element('p').update(msg));
}
</script>
</head>
<body><div>
<label for='txtLength'>Length:</label><input type='text' id='txtLength' value='10000'>
<br><label for='txtLoops'>Loops:</label><input type='text' id='txtLoops' value='10'>
<div id='checkboxes'></div>
<br><input type='button' id='btnTest' value='Test'>
<hr>
<div id='log'></div>
</div></body>
</html>
Theo mặc định Uint8Array
, Uint16Array
và Uint32Array
lớp giữ số không như giá trị của nó, do đó bạn không cần bất kỳ kỹ thuật đầy phức tạp, chỉ cần làm:
var ary = new Uint8Array(10);
tất cả các phần tử của mảng ary
sẽ là số không theo mặc định.
Array.isArray(ary)
là false
. Độ dài cũng chỉ đọc để bạn không thể đẩy các mục mới vào đó như vớiary.push
0
làm giá trị mặc định của chúng.
Array.from(new Uint8Array(10))
sẽ cung cấp một mảng bình thường.
Array(n).fill(0)
Chrome nếu thứ bạn thực sự cần là một Mảng JS. Tuy nhiên, nếu bạn có thể sử dụng TypedArray, thì điều này thậm chí còn nhanh hơn nhiều .fill(0)
, đặc biệt là nếu bạn có thể sử dụng giá trị khởi tạo mặc định là 0
. Dường như không có một hàm tạo nào có giá trị điền và độ dài, như cách mà C ++ std::vector
có. Dường như đối với bất kỳ giá trị khác không, bạn phải xây dựng TypedArray bằng 0 và sau đó điền vào nó. : /
Nếu bạn sử dụng ES6, bạn có thể sử dụng Array.from () như thế này:
Array.from({ length: 3 }, () => 0);
//[0, 0, 0]
Có kết quả tương tự như
Array.from({ length: 3 }).map(() => 0)
//[0, 0, 0]
Bởi vì
Array.from({ length: 3 })
//[undefined, undefined, undefined]
function makeArrayOf(value, length) {
var arr = [], i = length;
while (i--) {
arr[i] = value;
}
return arr;
}
makeArrayOf(0, 5); // [0, 0, 0, 0, 0]
makeArrayOf('x', 3); // ['x', 'x', 'x']
Lưu ý rằng while
thường là hiệu quả hơn for-in
, forEach
vv
i
biến cục bộ không liên quan? length
được truyền bằng giá trị để bạn có thể giảm giá trị trực tiếp.
arr[i] = value
) rất chậm . Nó nhanh hơn nhiều để lặp lại từ đầu đến cuối và sử dụng arr.push(value)
. Thật khó chịu, vì tôi thích phương pháp của bạn.
sử dụng ký hiệu đối tượng
var x = [];
không điền? giống...
var x = [0,0,0,0,0,0];
chứa đầy 'không xác định' ...
var x = new Array(7);
ký hiệu obj với số không
var x = [];
for (var i = 0; i < 10; i++) x[i] = 0;
Là một lưu ý phụ, nếu bạn sửa đổi nguyên mẫu của Array, cả hai
var x = new Array();
và
var y = [];
sẽ có những sửa đổi nguyên mẫu
Ở mức độ nào, tôi sẽ không quá quan tâm đến hiệu quả hoặc tốc độ của hoạt động này, có rất nhiều điều khác mà bạn có thể sẽ làm lãng phí và tốn kém hơn nhiều so với việc tạo ra một mảng có độ dài tùy ý có chứa số không.
null
s trong mảng này -var x = new Array(7);
new Array(7)
không không tạo ra một mảng "tràn ngập không xác định". Nó tạo ra một mảng trống có chiều dài 7.
(new Array(10)).fill(0)
.
Tôi đã thử nghiệm tất cả các kết hợp phân bổ trước / không phân bổ trước, đếm lên / xuống và các vòng lặp for / while trong IE 6/7/8, Firefox 3.5, Chrome và Opera.
Các chức năng bên dưới luôn là nhanh nhất hoặc cực kỳ gần gũi trong Firefox, Chrome và IE8 và không chậm hơn nhiều so với nhanh nhất trong Opera và IE 6. Theo tôi, đây cũng là cách đơn giản và rõ ràng nhất. Tôi đã tìm thấy một số trình duyệt trong đó phiên bản vòng lặp while nhanh hơn một chút, vì vậy tôi cũng đưa nó vào để tham khảo.
function newFilledArray(length, val) {
var array = [];
for (var i = 0; i < length; i++) {
array[i] = val;
}
return array;
}
hoặc là
function newFilledArray(length, val) {
var array = [];
var i = 0;
while (i < length) {
array[i++] = val;
}
return array;
}
var array = []
khai báo vào phần đầu tiên của vòng lặp for, chỉ cách nhau bằng dấu phẩy.
length
giá trị đã cho để nó không thay đổi liên tục. Mang lại một mảng dài 1 triệu từ 0 đến 8 trên máy của tôi.
for (i = 0, array = []; i < length; ++i) array[i] = val;
.. Ít khối hơn? ... dù sao đi nữa, ... nếu tôi đặt array.length
mảng mới theo chiều dài .. tôi dường như tăng thêm 10% -15% tốc độ trong FF ... trong Chrome, dường như tăng gấp đôi tốc độ -> var i, array = []; array.length = length; while(i < length) array[i++] = val;
(vẫn nhanh hơn nếu tôi để nó như một for
vòng lặp ... nhưng init không còn cần thiết nữa, vì vậy while
dường như nhanh hơn trên phiên bản này)
Nếu bạn cần tạo nhiều mảng không có độ dài khác nhau trong quá trình thực thi mã của mình, cách nhanh nhất tôi tìm thấy để đạt được điều này là tạo một mảng 0 một lần , sử dụng một trong các phương pháp được đề cập trong chủ đề này, có độ dài mà bạn biết sẽ không bao giờ vượt quá, và sau đó cắt mảng đó khi cần thiết.
Ví dụ: (sử dụng hàm từ câu trả lời đã chọn ở trên để khởi tạo mảng), tạo một mảng có độ dài maxLpm có độ dài bằng 0 , như một biến hiển thị cho mã cần mảng 0:
var zero = newFilledArray(maxLength, 0);
Bây giờ cắt mảng mọi điều này bạn cần một điền mảng zero chiều dài requiredLength < maxLength :
zero.slice(0, requiredLength);
Tôi đã tạo ra các mảng không đầy hàng ngàn lần trong khi thực thi mã của mình, điều này đã tăng tốc quá trình rất nhiều.
Tôi không có gì chống lại:
Array.apply(null, Array(5)).map(Number.prototype.valueOf,0);
new Array(5+1).join('0').split('').map(parseFloat);
được đề xuất bởi Zertosh, nhưng trong một phần mở rộng mảng ES6 mới cho phép bạn thực hiện điều này một cách tự nhiên bằng fill
phương pháp. Bây giờ IE edge, Chrome và FF hỗ trợ nó, nhưng kiểm tra bảng tương thích
new Array(3).fill(0)
sẽ cung cấp cho bạn [0, 0, 0]
. Bạn có thể điền vào mảng với bất kỳ giá trị nào như new Array(5).fill('abc')
(ngay cả các đối tượng và các mảng khác).
Trên hết, bạn có thể sửa đổi các mảng trước đó bằng cách điền:
arr = [1, 2, 3, 4, 5, 6]
arr.fill(9, 3, 5) # what to fill, start, end
cung cấp cho bạn: [1, 2, 3, 9, 9, 6]
Cách tôi thường làm (và nhanh chóng tuyệt vời) đang sử dụng Uint8Array
. Ví dụ: tạo một vectơ không chứa các phần tử 1M:
var zeroFilled = [].slice.apply(new Uint8Array(1000000))
Tôi là người dùng Linux và luôn làm việc cho tôi, nhưng một khi một người bạn sử dụng máy Mac có một số yếu tố khác không. Tôi nghĩ rằng máy của anh ta đã gặp trục trặc, nhưng đây vẫn là cách an toàn nhất mà chúng tôi tìm thấy để khắc phục nó:
var zeroFilled = [].slice.apply(new Uint8Array(new Array(1000000))
Đã chỉnh sửa
Chrome 25.0.1364.160
Firefox 20.0
Thiếu bài kiểm tra quan trọng nhất (ít nhất là đối với tôi): bài kiểm tra Node.js. Tôi nghi ngờ nó gần với điểm chuẩn của Chrome.
_.range(0, length - 1, 0);
Hoặc nếu bạn có một mảng hiện có và bạn muốn một mảng có cùng độ dài
array.map(_.constant(0));
_.range(0, length, 0)
, tôi tin. Lodash không bao gồm giá trị cuối
Kể từ ECMAScript2016 , có một lựa chọn rõ ràng cho các mảng lớn.
Vì câu trả lời này vẫn hiển thị gần đầu trên các tìm kiếm của google, đây là câu trả lời cho năm 2017.
Đây là một jsbench hiện tại với một vài chục phương thức phổ biến, bao gồm nhiều phương pháp được đề xuất cho đến nay cho câu hỏi này. Nếu bạn tìm thấy một phương pháp tốt hơn xin vui lòng thêm, ngã ba và chia sẻ.
Tôi muốn lưu ý rằng không có cách hiệu quả nhất thực sự để tạo ra một mảng có độ dài bằng 0 tùy ý. Bạn có thể tối ưu hóa cho tốc độ, hoặc cho sự rõ ràng và khả năng bảo trì - có thể được coi là sự lựa chọn hiệu quả hơn tùy thuộc vào nhu cầu của dự án.
Khi tối ưu hóa tốc độ, bạn muốn: tạo mảng bằng cú pháp bằng chữ; đặt độ dài, khởi tạo biến lặp và lặp qua mảng bằng vòng lặp while. Đây là một ví dụ.
const arr = [];
arr.length = 120000;
let i = 0;
while (i < 120000) {
arr[i] = 0;
i++;
}
Một cách thực hiện khác có thể là:
(arr = []).length = n;
let i = 0;
while (i < n) {
arr[i] = 0;
i++;
}
Nhưng tôi thực sự không khuyến khích sử dụng phương pháp cấy ghép thứ hai này trong thực tế vì nó không rõ ràng và không cho phép bạn duy trì phạm vi khối trên biến mảng của mình.
Chúng nhanh hơn đáng kể so với điền vào một vòng lặp for và nhanh hơn khoảng 90% so với phương pháp tiêu chuẩn
const arr = Array(n).fill(0);
Nhưng phương pháp điền này vẫn là lựa chọn hiệu quả nhất cho các mảng nhỏ hơn do tính rõ ràng, đồng nhất và khả năng bảo trì của nó. Sự khác biệt về hiệu suất có thể sẽ không giết bạn trừ khi bạn tạo ra nhiều mảng với độ dài theo thứ tự hàng nghìn trở lên.
Một vài lưu ý quan trọng khác. Hầu hết các hướng dẫn phong cách khuyên bạn không còn sử dụng var
mà không có lý do rất đặc biệt khi sử dụng ES6 trở lên. Sử dụng const
cho các biến sẽ không được xác định lại và let
cho các biến sẽ. Các MDN và Hướng dẫn Phong cách Airbnb của là nơi tuyệt vời để đi để biết thêm thông tin về thực hành tốt nhất. Các câu hỏi không phải là về cú pháp, nhưng điều quan trọng là mọi người mới biết về JS đều biết về các tiêu chuẩn mới này khi tìm kiếm thông qua các câu trả lời cũ và mới.
Để tạo một Mảng hoàn toàn mới
new Array(arrayLength).fill(0);
Để thêm một số giá trị ở cuối Mảng hiện có
[...existingArray, ...new Array(numberOfElementsToAdd).fill(0)]
//**To create an all new Array**
console.log(new Array(5).fill(0));
//**To add some values at the end of an existing Array**
let existingArray = [1,2,3]
console.log([...existingArray, ...new Array(5).fill(0)]);
Không thấy phương pháp này trong câu trả lời, vì vậy đây là:
"0".repeat( 200 ).split("").map( parseFloat )
Kết quả là bạn sẽ nhận được mảng có giá trị bằng không có độ dài 200:
[ 0, 0, 0, 0, ... 0 ]
Tôi không chắc chắn về hiệu suất của mã này, nhưng nó không phải là vấn đề nếu bạn sử dụng nó cho các mảng tương đối nhỏ.
const arr = Array.from({ length: 10 }).fill(0)
Đây concat
là phiên bản nhanh hơn nhiều trong các thử nghiệm của tôi trên Chrome (2013/03/21). Khoảng 200ms cho 10.000.000 phần tử so với 675 cho init thẳng.
function filledArray(len, value) {
if (len <= 0) return [];
var result = [value];
while (result.length < len/2) {
result = result.concat(result);
}
return result.concat(result.slice(0, len-result.length));
}
Phần thưởng: nếu bạn muốn điền vào mảng của mình bằng Chuỗi, đây là một cách ngắn gọn để làm điều đó (không hoàn toàn nhanh như concat
vậy):
function filledArrayString(len, value) {
return new Array(len+1).join(value).split('');
}
Tôi đã thử nghiệm câu trả lời tuyệt vời của TJ Crowder và đã đưa ra một sự hợp nhất đệ quy dựa trên giải pháp concat vượt trội hơn bất kỳ thử nghiệm nào trong Chrome (tôi không thử nghiệm các trình duyệt khác).
function makeRec(len, acc) {
if (acc == null) acc = [];
if (len <= 1) return acc;
var b = makeRec(len >> 1, [0]);
b = b.concat(b);
if (len & 1) b = b.concat([0]);
return b;
},
gọi phương thức với makeRec(29)
.
Thế còn new Array(51).join('0').split('')
?
.map(function(a){return +a})
?
Có thể đáng để chỉ ra, Array.prototype.fill
đã được thêm vào như một phần của đề xuất ECMAScript 6 (Harmony) . Tôi thà đi với polyfill được viết dưới đây, trước khi xem xét các tùy chọn khác được đề cập trên chuỗi.
if (!Array.prototype.fill) {
Array.prototype.fill = function(value) {
// Steps 1-2.
if (this == null) {
throw new TypeError('this is null or not defined');
}
var O = Object(this);
// Steps 3-5.
var len = O.length >>> 0;
// Steps 6-7.
var start = arguments[1];
var relativeStart = start >> 0;
// Step 8.
var k = relativeStart < 0 ?
Math.max(len + relativeStart, 0) :
Math.min(relativeStart, len);
// Steps 9-10.
var end = arguments[2];
var relativeEnd = end === undefined ?
len : end >> 0;
// Step 11.
var final = relativeEnd < 0 ?
Math.max(len + relativeEnd, 0) :
Math.min(relativeEnd, len);
// Step 12.
while (k < final) {
O[k] = value;
k++;
}
// Step 13.
return O;
};
}
Ngắn nhất cho mã vòng lặp
a=i=[];for(;i<100;)a[i++]=0;
edit:
for(a=i=[];i<100;)a[i++]=0;
or
for(a=[],i=100;i--;)a[i]=0;
Phiên bản var an toàn
var a=[],i=0;for(;i<100;)a[i++]=0;
edit:
for(var i=100,a=[];i--;)a[i]=0;
n
, điều này sẽ ngắn hơn:for(var a=[];n--;a[n]=0);
let filled = [];
filled.length = 10;
filled.fill(0);
console.log(filled);
Chức năng nhanh nhất của tôi sẽ là:
function newFilledArray(len, val) {
var a = [];
while(len--){
a.push(val);
}
return a;
}
var st = (new Date()).getTime();
newFilledArray(1000000, 0)
console.log((new Date()).getTime() - st); // returned 63, 65, 62 milliseconds
Sử dụng tính năng đẩy và dịch chuyển riêng để thêm các mục vào mảng nhanh hơn nhiều (khoảng 10 lần) so với khai báo phạm vi mảng và tham chiếu từng mục để đặt giá trị của nó.
fyi: Tôi liên tục nhận được thời gian nhanh hơn với vòng lặp đầu tiên, đó là đếm ngược, khi chạy nó trong fireorms (phần mở rộng firefox).
var a = [];
var len = 1000000;
var st = (new Date()).getTime();
while(len){
a.push(0);
len -= 1;
}
console.log((new Date()).getTime() - st); // returned 863, 894, 875 milliseconds
st = (new Date()).getTime();
len = 1000000;
a = [];
for(var i = 0; i < len; i++){
a.push(0);
}
console.log((new Date()).getTime() - st); // returned 1155, 1179, 1163 milliseconds
Tôi muốn biết TJ Crowder làm gì với điều đó? :-)
while (len--)
.. mất thời gian xử lý của tôi từ khoảng 60ms đến khoảng 54ms
Tôi biết tôi đã có proto'd này ở đâu đó :)
Array.prototype.init = function(x,n)
{
if(typeof(n)=='undefined') { n = this.length; }
while (n--) { this[n] = x; }
return this;
}
var a = (new Array(5)).init(0);
var b = [].init(0,4);
Chỉnh sửa: kiểm tra
Để đáp ứng với Joshua và các phương pháp khác, tôi đã chạy điểm chuẩn của riêng mình và tôi thấy kết quả hoàn toàn khác với những phương pháp được báo cáo.
Đây là những gì tôi đã thử nghiệm:
//my original method
Array.prototype.init = function(x,n)
{
if(typeof(n)=='undefined') { n = this.length; }
while (n--) { this[n] = x; }
return this;
}
//now using push which I had previously thought to be slower than direct assignment
Array.prototype.init2 = function(x,n)
{
if(typeof(n)=='undefined') { n = this.length; }
while (n--) { this.push(x); }
return this;
}
//joshua's method
function newFilledArray(len, val) {
var a = [];
while(len--){
a.push(val);
}
return a;
}
//test m1 and m2 with short arrays many times 10K * 10
var a = new Date();
for(var i=0; i<10000; i++)
{
var t1 = [].init(0,10);
}
var A = new Date();
var b = new Date();
for(var i=0; i<10000; i++)
{
var t2 = [].init2(0,10);
}
var B = new Date();
//test m1 and m2 with long array created once 100K
var c = new Date();
var t3 = [].init(0,100000);
var C = new Date();
var d = new Date();
var t4 = [].init2(0,100000);
var D = new Date();
//test m3 with short array many times 10K * 10
var e = new Date();
for(var i=0; i<10000; i++)
{
var t5 = newFilledArray(10,0);
}
var E = new Date();
//test m3 with long array created once 100K
var f = new Date();
var t6 = newFilledArray(100000, 0)
var F = new Date();
Các kết quả:
IE7 deltas:
dA=156
dB=359
dC=125
dD=375
dE=468
dF=412
FF3.5 deltas:
dA=6
dB=13
dC=63
dD=8
dE=12
dF=8
Vì vậy, bằng cách tính toán đẩy của tôi thực sự là chậm hơn nói chung nhưng hoạt động tốt hơn với các mảng dài hơn trong FF nhưng tệ hơn trong IE chỉ nói chung là bất ngờ (quel ngạc nhiên).
b = []...
) nhanh hơn 10-15% so với phương pháp thứ nhất, nhưng nó chậm hơn 10 lần so với câu trả lời của Joshua.
else {this.length=n;}
sau this.length
-check. Điều này sẽ rút ngắn một mảng đã có sẵn nếu cần thiết khi định nghĩa lại init
nó thành một độ dài khác n
.
Hàm ẩn danh:
(function(n) { while(n-- && this.push(0)); return this; }).call([], 5);
// => [0, 0, 0, 0, 0]
Ngắn hơn một chút với vòng lặp for:
(function(n) { for(;n--;this.push(0)); return this; }).call([], 5);
// => [0, 0, 0, 0, 0]
Làm việc với bất kỳ Object
, chỉ cần thay đổi những gì bên trong this.push()
.
Bạn thậm chí có thể lưu chức năng:
function fill(size, content) {
for(;size--;this.push(content));
return this;
}
Gọi nó bằng cách sử dụng:
var helloArray = fill.call([], 5, 'hello');
// => ['hello', 'hello', 'hello', 'hello', 'hello']
Thêm các phần tử vào một mảng đã có sẵn:
var helloWorldArray = fill.call(helloArray, 5, 'world');
// => ['hello', 'hello', 'hello', 'hello', 'hello', 'world', 'world', 'world', 'world', 'world']