วิธีที่มีประสิทธิภาพมากที่สุดในการเชื่อมต่ออาร์เรย์ N คืออะไร?


251

วิธีที่มีประสิทธิภาพมากที่สุดในการเชื่อมอาเรย์ของออบเจ็กต์ N กับ JavaScript คืออะไร?

อาร์เรย์ไม่แน่นอนและผลลัพธ์สามารถเก็บไว้ในหนึ่งในอาร์เรย์อินพุต


2
มีความเป็นไปได้ที่จะทำซ้ำของMerge / Array of Array ใน JavaScript?
rofrol

คำตอบ:


323

หากคุณเชื่อมต่อมากกว่าสองอาร์เรย์concat()เป็นวิธีที่จะไปเพื่อความสะดวกและประสิทธิภาพที่น่าจะเป็น

var a = [1, 2], b = ["x", "y"], c = [true, false];
var d = a.concat(b, c);
console.log(d); // [1, 2, "x", "y", true, false];

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

var a = [1, 2], b = ["x", "y"];
a.push.apply(a, b);
console.log(a); // [1, 2, "x", "y"];

ใน ECMAScript 2015 และใหม่กว่านี้สามารถลดลงได้อีก

a.push(...b)

อย่างไรก็ตามดูเหมือนว่าสำหรับอาร์เรย์ขนาดใหญ่ (จากสมาชิก 100,000 คนหรือมากกว่านั้น) เทคนิคที่ผ่านอาร์เรย์ขององค์ประกอบต่างๆpush(ไม่ว่าจะใช้apply()หรือตัวดำเนินการแพร่กระจาย ECMAScript 2015) อาจล้มเหลวได้ สำหรับอาร์เรย์ดังกล่าวการใช้การวนซ้ำเป็นวิธีที่ดีกว่า ดูhttps://stackoverflow.com/a/17368101/96100สำหรับรายละเอียด


1
ฉันเชื่อว่าการทดสอบของคุณอาจมีข้อผิดพลาด: a.concat(b)กรณีทดสอบดูเหมือนจะไม่จำเป็นต้องทำสำเนาของอาร์เรย์aแล้วโยนมันทิ้งไป
ninjagecko

1
@ninjagecko: ถูกต้อง ฉันปรับปรุงมันjsperf.com/concatperftest/6 สำหรับกรณีเฉพาะของการสร้างอาร์เรย์ใหม่ที่เชื่อมสองอาร์เรย์ที่มีอยู่เข้าด้วยกันconcat()โดยทั่วไปจะปรากฏขึ้นเร็วขึ้น สำหรับกรณีที่เชื่อมต่ออาเรย์เข้ากับอาเรย์ที่มีอยู่เดิมpush()เป็นวิธีที่จะไป ฉันปรับปรุงคำตอบของฉัน
Tim Down

16
ฉันสามารถยืนยันได้ว่าการขยายอาเรย์เดี่ยวด้วยอาร์เรย์ใหม่หลายอันโดยใช้วิธีการ push.apply ทำให้เกิดข้อได้เปรียบด้านประสิทธิภาพอย่างมาก (~ 100x) ผ่านการโทรแบบง่าย ฉันกำลังจัดการกับรายการที่สั้นมากของรายการจำนวนเต็มสั้น ๆ ใน v8 / node.js
chbrown

1
วิธีที่กระชับยิ่งขึ้นคือ a.push (... b);
dinvlad

1
@dinvlad: จริง แต่เฉพาะในสภาพแวดล้อม ES6 ฉันได้เพิ่มบันทึกคำตอบของฉันแล้ว
Tim Down

158
[].concat.apply([], [array1, array2, ...])

แก้ไข : พิสูจน์ประสิทธิภาพ: http://jsperf.com/multi-array-concat/7

แก้ไข 2 : ทิม Supinie กล่าวถึงในความคิดเห็นที่ว่านี้อาจทำให้ล่ามเกินขนาดโทรสแต็ค นี่อาจขึ้นอยู่กับเอ็นจิ้น js แต่ฉันได้รับ "ขนาดการโทรสูงสุดเกินกว่า" ใน Chrome เป็นอย่างน้อย กรณีทดสอบ: [].concat.apply([], Array(300000).fill().map(_=>[1,2,3])). (ฉันยังได้รับข้อผิดพลาดเดียวกันโดยใช้คำตอบที่ได้รับการยอมรับในปัจจุบันดังนั้นหนึ่งคาดการณ์กรณีการใช้งานดังกล่าวหรือการสร้างห้องสมุดสำหรับผู้อื่นการทดสอบพิเศษอาจจำเป็น


3
@ c69: ดูเหมือนว่าจะมีประสิทธิภาพเท่ากับคำตอบที่เลือกของ. push (#, #, ... , #) ซ้ำ ๆ อย่างน้อย jsperf.com/multi-array-concatคำตอบที่เลือกโดย Tim Down อาจมีข้อผิดพลาด ลิงค์นี้เป็นการเปรียบเทียบประสิทธิภาพของการเข้าร่วมหลายอาร์เรย์ตามคำถามที่ถาม (ไม่ใช่แค่ 2) มีการทดสอบความยาวหลาย ๆ
ninjagecko

IMO นี่เป็นวิธีที่มีประสิทธิภาพมากที่สุดในการ "ผสาน" n อาร์เรย์ทำได้ดี
Eric Uldall

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

3
ด้วย ES6 และตัวดำเนินการที่แพร่กระจายทำให้ง่ายขึ้น: [] .concat (... [array1, array2, ... ]) ดีจุดสามจุดที่สองนั้นค่อนข้างโชคร้าย สามคนแรกคือผู้ให้บริการ พัฒนา
spread.mozilla.org/en/docs/Web/JavaScript/Reference/ …

Eydrian: ฉันพยายามหลีกเลี่ยงตัวดำเนินการสเปรดเองเพราะมันไม่มีประสิทธิภาพมาก แต่ฉันก็ยังไม่แน่ใจหากนั่นเป็นเพราะการใช้งานนั้นยังไม่สมบูรณ์หรือความหมายของข้อกำหนด ES6 ต้องการการยกที่หนักกว่าเล็กน้อย (นั่นจะไม่ดีขึ้นเลย ) ยังไม่ได้ใช้การวัดประสิทธิภาพใด ๆ ในกรณีนี้
ninjagecko

34

สำหรับคนที่ใช้ ES2015 (ES6)

ตอนนี้คุณสามารถใช้ไวยากรณ์การแพร่กระจายเพื่อเชื่อมต่ออาร์เรย์:

const arr1 = [0, 1, 2],
      arr2 = [3, 4, 5];

const result1 = [...arr1, ...arr2]; // -> [0, 1, 2, 3, 4, 5]

// or...

const result2 = [...arr2, ...arr1]; // -> [3, 4, 5, 0, 1, 2]

มันมีประสิทธิภาพแค่ไหน? จากสิ่งที่ฉันได้ทดสอบนี้ช้ามากสำหรับอาร์เรย์ที่มีวัตถุดู: jsperf.com/array-concat-vs-array-push-vs-array-spread/1
hitautodestruct

28

concat()วิธีการที่ใช้ในการเข้าร่วมสองคนหรือมากกว่าอาร์เรย์ มันไม่เปลี่ยนอาร์เรย์ที่มีอยู่ แต่จะส่งกลับเฉพาะสำเนาของอาร์เรย์ที่เข้าร่วม

array1 = array1.concat(array2, array3, array4, ..., arrayN);

1
บางครั้งฉันเกลียดจาวาสคริปต์ที่จะไม่ดัดแปลงอาร์เรย์ดั้งเดิม 🙄
Vincent Hoch-Drei

@ VincentHoch-Drei concatใช้สำหรับสร้างอาร์เรย์ใหม่โดยไม่ต้องกลายพันธุ์อาร์เรย์เดิม หากคุณต้องการอัปเดตarray1คุณต้องใช้array1.push(...array2, ...array3, ...array4)
adiga

24

ใช้ Array.prototype.concat.apply เพื่อจัดการการเรียงต่อกันหลาย ๆ อาร์เรย์:

var resultArray = Array.prototype.concat.apply([], arrayOfArraysToConcat);

ตัวอย่าง:

var a1 = [1, 2, 3],
    a2 = [4, 5],
    a3 = [6, 7, 8, 9];
Array.prototype.concat.apply([], [a1, a2, a3]); // [1, 2, 3, 4, 5, 6, 7, 8, 9]

1
ฉันชอบอันนี้! ทำงานได้อย่างง่ายดายด้วยจำนวนอาร์เรย์ที่หลากหลายเพื่อต่อเชื่อม +1
Joel

14

หากคุณอยู่ระหว่างการวางท่อผลลัพธ์ผ่านแผนที่ / ตัวกรอง / การเรียงลำดับ ฯลฯ และคุณต้องการเชื่อมต่ออาร์เรย์ของอาร์เรย์คุณสามารถใช้ reduce

let sorted_nums = ['1,3', '4,2']
  .map(item => item.split(','))   // [['1', '3'], ['4', '2']]
  .reduce((a, b) => a.concat(b))  // ['1', '3', '4', '2']
  .sort()                         // ['1', '2', '3', '4']

14

สำหรับอาร์เรย์ที่มีหลายอาร์เรย์และ ES6 ให้ใช้

Array.prototype.concat(...arr);

ตัวอย่างเช่น:

const arr = [[1, 2, 3], [4, 5, 6], [7, 8 ,9]];
const newArr = Array.prototype.concat(...arr);
// output: [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ]

1
newArr = Array.from(new Set(newArr));นอกจากนี้คุณสามารถลบองค์ประกอบที่ซ้ำกันโดยใช้
Darius

ทำไมใน typescript จึงกลายเป็นany[]? การพิมพ์มี - แปลก
Simon_Weaver

ที่จริงแล้วมันไม่มีประสิทธิภาพอย่างน่ากลัวในโวลุ่มอาเรย์ขนาดใหญ่ jsperf.com/flatten-array-203948 [].concat.apply([], ...arr)มีประสิทธิภาพดีกว่าในปริมาณมาก
colemars

7

ES6 Spreadตอนนี้เราสามารถรวมอาร์เรย์หลายคนโดยใช้ แทนที่จะใช้concat()เพื่อต่อเชื่อมอาเรย์ลองใช้ไวยากรณ์สเปรดเพื่อรวมหลายอาเรย์เป็นหนึ่งอาเรย์แบน เช่น:

var a = [1,2];
var b = [3,4];
var c = [5,6,7];
var d = [...a, ...b, ...c];
// resulting array will be like d = [1,2,3,4,5,6,7]

5

แก้ไขแบบนี้

let arr = [[1, 2], [3, 4], [5, 6]];
 console.log([].concat(...arr));

โซลูชั่นที่สมบูรณ์แบบ
nehem

4

คุณสามารถใช้เว็บไซต์jsperf.comเพื่อเปรียบเทียบประสิทธิภาพ นี่คือลิงค์ไปยังconcat concat

เพิ่มการเปรียบเทียบระหว่าง:

var c = a.concat(b);

และ:

var c = [];
for (i = 0; i < a.length; i++) {
    c.push(a[i]);
}
for (j = 0; j < b.length; j++) {
    c.push(b[j]);
}

ที่สองช้ากว่าโครเมี่ยมเกือบ 10 เท่า


อย่างไรก็ตามคุณสามารถใช้งานpush.apply()ได้ซึ่งดูเหมือนจะเร็วกว่าconcat()ในทุกเบราว์เซอร์ยกเว้น Chrome ดูคำตอบของฉัน
Tim Down


3

นี่คือฟังก์ชั่นที่คุณสามารถต่อหลายอาร์เรย์ได้

function concatNarrays(args) {
    args = Array.prototype.slice.call(arguments);
    var newArr = args.reduce( function(prev, next) {
       return prev.concat(next) ;
    });

    return newArr;
}

ตัวอย่าง -

console.log(concatNarrays([1, 2, 3], [5, 2, 1, 4], [2,8,9]));

จะส่งออก

[1,2,3,5,2,1,4,2,8,9]

3

ผสานอาร์เรย์ด้วยการกด:

const array1 = [2, 7, 4];
const array2 = [3, 5,9];
array1.push(...array2);
console.log(array1)

ใช้ตัวดำเนินการConcatและSpread:

const array1 = [1,2];
const array2 = [3,4];

// Method 1: Concat 
const combined1 = [].concat(array1, array2);

// Method 2: Spread
const combined2 = [...array1, ...array2];

console.log(combined1);
console.log(combined2);


2

หากคุณมีอาร์เรย์ของอาร์เรย์และต้องการเชื่อมองค์ประกอบเข้าด้วยกันให้ลองใช้รหัสต่อไปนี้ (ต้องใช้ ES2015):

let arrOfArr = [[1,2,3,4],[5,6,7,8]];
let newArr = [];
for (let arr of arrOfArr) {
    newArr.push(...arr);
}

console.log(newArr);
//Output: [1,2,3,4,5,6,7,8];

หรือถ้าคุณเป็นนักเขียนโปรแกรมฟังก์ชั่น

let arrOfArr = [[1,2,3,4],[5,6,7,8]];
let newArr = arrOfArr.reduce((result,current)=>{
    result.push(...current);
    return result;
});

console.log(newArr);
//Output: [1,2,3,4,5,6,7,8];

หรือดียิ่งขึ้นด้วยไวยากรณ์ ES5 โดยไม่มีตัวดำเนินการสเปรด

var arrOfArr = [[1,2,3,4],[5,6,7,8]];
var newArr = arrOfArr.reduce((result,current)=>{
    return result.concat(current);
});
console.log(newArr);
//Output: [1,2,3,4,5,6,7,8];

วิธีนี้มีประโยชน์ถ้าคุณไม่ทราบหมายเลข ของอาร์เรย์ที่เวลารหัส


2

ย่อด้วย ES6

new Set([].concat(...Array));

การทำเช่นนี้จะเป็นการเชื่อมโยงและสร้างหลายอาร์เรย์ที่ไม่ซ้ำกัน

การสาธิตเกี่ยวกับ codepen


มันจะทำอย่างไร แต่จะลบรายการที่ซ้ำกันออกไป .. จะเกิดอะไรขึ้นถ้าฉันไม่ต้องการลบอาร์เรย์ที่ซ้ำกันออกไป
Krunal Shah

new Set()จะลบรายการที่ซ้ำกัน เพียงลบออก [].concat(...Array)
ronaldtgi

ฉันต้องการใช้ชุดใหม่ ([]. concat (... Array)); แต่ฉันต้องการลบรายการที่ซ้ำกันออกไปด้วยในนิพจน์เดียว เป็นไปได้ไหม ?
Krunal Shah

1

โดยที่ 'n' คือจำนวนอาร์เรย์บางตัวซึ่งอาจเป็นอาร์เรย์ของอาร์เรย์ . .

var answer = _.reduce (n, ฟังก์ชั่น (a, b) {return a.concat (b)})


1

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

เกณฑ์มาตรฐาน: https://jsperf.com/concat-small-arrays-vs-push-vs-loop/


0

ลองนี้:

i=new Array("aaaa", "bbbb");
j=new Array("cccc", "dddd");

i=i.concat(j);

@reggie คุณทั้งคู่คัดลอกมาจากแหล่งเดียวกัน)
I.devries

ไม่ฉันตรวจสอบข้อมูลในลิงก์เดียวกันกับคุณ ilovethecode.com/Javascript/Javascript-Tutorials-How_To-Easy/ …
JAiro

ใช่ ... ฉันเดาว่าเราได้รับมาจากแหล่งเดียวกัน: D
reggie

อย่างน้อย @JAiro เปลี่ยนเนื้อหาของอาร์เรย์ @reggie ไม่ได้ :)
dogbane

มันจะเหมือนกันสิ่งที่สำคัญคือช่วยให้ผู้คนในการแก้ไขปัญหาของ :)
Jairo

0

หากอาร์เรย์ N ได้รับจากฐานข้อมูลและไม่ใช่ฮาร์ดโค้ดฉันจะทำเช่นนี้โดยใช้ ES6

let get_fruits = [...get_fruits , ...DBContent.fruit];
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.