การเรียงลำดับอาร์เรย์ใหม่


100

พูดว่าฉันมีอาร์เรย์ที่มีลักษณะดังนี้:

var playlist = [
    {artist:"Herbie Hancock", title:"Thrust"},
    {artist:"Lalo Schifrin", title:"Shifting Gears"},
    {artist:"Faze-O", title:"Riding High"}
];

ฉันจะย้ายองค์ประกอบไปยังตำแหน่งอื่นได้อย่างไร

ฉันต้องการย้ายตัวอย่างเช่น{artist:"Lalo Schifrin", title:"Shifting Gears"}ไปยังจุดสิ้นสุด

ฉันลองใช้ Splice ดังนี้:

var tmp = playlist.splice(2,1);
playlist.splice(2,0,tmp);

แต่มันไม่ได้ผล


3
"ใช้งานไม่ได้" หมายความว่าอะไร - มันส่งข้อผิดพลาดไม่เปลี่ยนแปลงอะไรเลยมันเปลี่ยนอาร์เรย์ในแบบที่คุณไม่ได้ตั้งใจหรือไม่ มันดูสมเหตุสมผลสำหรับฉัน
Jacob Mattison

คำตอบ:


227

ไวยากรณ์ของArray.spliceคือ:

yourArray.splice(index, howmany, element1, /*.....,*/ elementX);

ที่ไหน:

  • ดัชนีคือตำแหน่งในอาร์เรย์ที่คุณต้องการเริ่มลบองค์ประกอบ
  • Howmanyคือจำนวนองค์ประกอบที่คุณต้องการลบออกจากดัชนี
  • element1, ... , elementXเป็นองค์ประกอบที่คุณต้องการแทรกจากตำแหน่งดัชนี

ซึ่งหมายความว่าsplice()สามารถใช้เพื่อลบองค์ประกอบเพิ่มองค์ประกอบหรือแทนที่องค์ประกอบในอาร์เรย์ขึ้นอยู่กับอาร์กิวเมนต์ที่คุณส่งผ่าน

โปรดทราบว่าจะส่งคืนอาร์เรย์ขององค์ประกอบที่ถูกลบออก

สิ่งที่ดีและทั่วไปจะเป็น:

Array.prototype.move = function (from, to) {
  this.splice(to, 0, this.splice(from, 1)[0]);
};

จากนั้นใช้:

var ar = [1,2,3,4,5];
ar.move(0,3);
alert(ar) // 2,3,4,1,5

แผนภาพ:

แผนภาพอัลกอริทึม


17
นี่เป็นคำตอบที่ดีและ splice () ภายใน splice () ทำงานได้ดี อย่างไรก็ตามควรสังเกตว่าการเพิ่มเมธอด move () ไปยังต้นแบบ Array เรียกว่า "Monkey Patching" และโดยทั่วไปถือว่าเป็นการปฏิบัติที่ไม่ดี stackoverflow.com/questions/5741877/…
Aaron Cicali

22

หากคุณทราบดัชนีคุณสามารถสลับองค์ประกอบได้อย่างง่ายดายด้วยฟังก์ชันง่ายๆเช่นนี้:

function swapElement(array, indexA, indexB) {
  var tmp = array[indexA];
  array[indexA] = array[indexB];
  array[indexB] = tmp;
}

swapElement(playlist, 1, 2);
// [{"artist":"Herbie Hancock","title":"Thrust"},
//  {"artist":"Faze-O","title":"Riding High"},
//  {"artist":"Lalo Schifrin","title":"Shifting Gears"}]

ดัชนีอาร์เรย์เป็นเพียงคุณสมบัติของออบเจ็กต์อาร์เรย์ดังนั้นคุณจึงสามารถสลับค่าได้


ขอบคุณ @CMS ถ้าฉันสลับค่าเฉลี่ยไม่ต้องการแทนที่ลำดับ ... ตัวอย่างเช่นถ้าฉันเลือกวัตถุที่ 3 เป็น 1 ตำแหน่งฉันต้องการสลับ 1 เป็น 2 และ 2 เป็น 3 เป็น 1
เปรี

14

นี่คือเวอร์ชันที่ไม่เปลี่ยนรูปสำหรับผู้ที่สนใจ:

function immutableMove(arr, from, to) {
  return arr.reduce((prev, current, idx, self) => {
    if (from === to) {
      prev.push(current);
    }
    if (idx === from) {
      return prev;
    }
    if (from < to) {
      prev.push(current);
    }
    if (idx === to) {
      prev.push(self[from]);
    }
    if (from > to) {
      prev.push(current);
    }
    return prev;
  }, []);
}

สวัสดีคุณช่วยอธิบายประโยชน์ของฟังก์ชันนี้ให้ฉันฟังจากคำตอบข้างต้นได้ไหม
Xogno

1
โซลูชันนี้ไม่ได้แก้ไของค์ประกอบดั้งเดิม แต่ส่งคืนอาร์เรย์ใหม่โดยมีการย้ายรายการ
chmanie

7

เปลี่ยน 2 เป็น 1 เป็นพารามิเตอร์แรกในการเรียกประกบเมื่อลบองค์ประกอบ:

var tmp = playlist.splice(1, 1);
playlist.splice(2, 0, tmp[0]);

1
ควรเป็น playlist.splice (2,0, tmp [0]); ขวา?
Crisboot

7

ด้วยES6คุณสามารถทำสิ่งนี้:

const swapPositions = (array, a ,b) => {
  [array[a], array[b]] = [array[b], array[a]]
}

let array = [1,2,3,4,5];
swapPositions(array,0,1);

/// => [2, 1, 3, 4, 5]

2
สิ่งนี้จะสลับตำแหน่งขององค์ประกอบทั้งสอง คำถามสำหรับการจัดลำดับใหม่
จำแนกตาม

6

คุณสามารถใช้วิธีการเรียงลำดับได้ตลอดเวลาหากคุณไม่ทราบว่าปัจจุบันบันทึกอยู่ที่ใด:

playlist.sort(function (a, b) {
    return a.artist == "Lalo Schifrin" 
               ? 1    // Move it down the list
               : 0;   // Keep it the same
});

1
แล้วไงreturn +(a.artist == "Lalo Schifrin")
Funkodebat

2
@ Funko คุณสามารถทำได้ถ้าคุณชอบความกะทัดรัดมากกว่าฟุ่มเฟื่อย
Andy E

2

แก้ไข: โปรดตรวจสอบคำตอบของ Andyเนื่องจากคำตอบของเขามาก่อนและนี่เป็นเพียงส่วนเสริมของเขาเท่านั้น

ฉันรู้ว่านี่เป็นคำถามเก่า แต่ฉันคิดว่ามันคุ้มค่าที่จะรวมArray.prototype.sort()ไว้

นี่คือตัวอย่างจาก MDN พร้อมกับลิงค์

var numbers = [4, 2, 5, 1, 3];
numbers.sort(function(a, b) {
  return a - b;
});
console.log(numbers);

// [1, 2, 3, 4, 5]

โชคดีที่มันไม่ได้ใช้กับตัวเลขเท่านั้น:

arr.sort([compareFunction])

compareFunction

ระบุฟังก์ชันที่กำหนดลำดับการจัดเรียง หากไม่ระบุอาร์เรย์จะถูกจัดเรียงตามค่าจุดรหัส Unicode ของอักขระแต่ละตัวตามการแปลงสตริงของแต่ละองค์ประกอบ

ฉันสังเกตเห็นว่าคุณสั่งซื้อโดยใช้ชื่อจริง:

let playlist = [
    {artist:"Herbie Hancock", title:"Thrust"},
    {artist:"Lalo Schifrin", title:"Shifting Gears"},
    {artist:"Faze-O", title:"Riding High"}
];

// sort by name
playlist.sort((a, b) => {
  if(a.artist < b.artist) { return -1; }
  if(a.artist > b.artist) { return  1; }

  // else names must be equal
  return 0;
});

โปรดทราบว่าหากคุณต้องการสั่งซื้อด้วยนามสกุลคุณจะต้องมีคีย์สำหรับทั้งสองfirst_name& last_nameหรือทำเวทมนตร์ regex ซึ่งฉันไม่สามารถทำ XD

หวังว่าจะช่วยได้ :)


นี่ควรเป็นการแก้ไขหรือแสดงความคิดเห็นในคำตอบนี้
Jared Smith

@JaredSmith อ๊ะ! ฉันไม่เห็นคำตอบของเขา ฉันมีคะแนนไม่เพียงพอหรืออะไรก็ตามที่จะแก้ไขคำถามของเขาและฉันไม่คิดว่าควรเพิ่มข้อมูลทั้งหมดนี้ในความคิดเห็น ดังนั้นจนกว่าจะมีคนแก้ไขคำถามของเขาฉันจะเพิ่มว่านี่เป็นส่วนเสริมสำหรับคำตอบของ Andy E (เหมือนที่ฉันควรทำ)
Jaacko Torus

ฉันคิดว่าตอนนี้สบายดี :)
Jared Smith


1

หากคุณต้องการย้ายเพียงรายการเดียวจากตำแหน่งใดตำแหน่งหนึ่งไปยังจุดสิ้นสุดของอาร์เรย์สิ่งนี้ควรได้ผล:

function toEnd(list, position) {
    list.push(list.splice(position, 1));
    return list;
}

หากคุณต้องการย้ายหลายรายการจากตำแหน่งใดตำแหน่งหนึ่งไปยังจุดสิ้นสุดคุณสามารถทำได้:

function toEnd(list, from, count) {
    list.push.apply(list, list.splice(from, count));
    return list;
}

หากคุณต้องการย้ายหลายรายการจากตำแหน่งใดตำแหน่งหนึ่งไปยังตำแหน่งที่กำหนดเองให้ลอง:

function move(list, from, count, to) {
    var args = [from > to ? to : to - count, 0];
    args.push.apply(args, list.splice(from, count));
    list.splice.apply(list, args);

    return list;
}

0

ในฐานะที่เป็นวิธีแก้ปัญหาที่ไม่ซับซ้อนคุณสามารถเรียก splice สองครั้งติดต่อกัน:

playlist.splice(playlist.length - 1, 1, ...playlist.splice(INDEX_TO_MOVE, 1))

ในทางกลับกันโซลูชันที่ไม่เปลี่ยนรูปแบบง่ายๆสามารถใช้ slice ได้เนื่องจากวิธีนี้จะส่งคืนสำเนาของส่วนจากอาร์เรย์ดั้งเดิมโดยไม่ต้องเปลี่ยนแปลง:

const copy = [...playlist.slice(0, INDEX_TO_MOVE - 1), ...playlist.slice(INDEX_TO_MOVE), ...playlist.slice(INDEX_TO_MOVE - 1, INDEX_TO_MOVE)]

-2

จัดลำดับงานใหม่ด้วยวิธีนี้

 var tmpOrder = playlist[oldIndex];
    playlist.splice(oldIndex, 1);
    playlist.splice(newIndex, 0, tmpOrder);

ฉันหวังว่านี่จะได้ผล


1
สิ่งนี้เพิ่มอะไรจากคำตอบที่มีอยู่
Jared Smith
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.