จะเรียงอาร์เรย์ 2 มิติตามค่าคอลัมน์ได้อย่างไร?


90

มีใครช่วยจัดเรียง Array 2 มิติใน JavaScript ได้ไหม

จะมีข้อมูลในรูปแบบต่อไปนี้:

[12, AAA]
[58, BBB]
[28, CCC]
[18, DDD]

ควรมีลักษณะดังนี้เมื่อจัดเรียง:

[12, AAA]
[18, DDD]
[28, CCC]
[58, BBB]

โดยพื้นฐานแล้วเรียงตามคอลัมน์แรก

ไชโย


3
นี่คือทุกสิ่งที่คุณต้องรู้: MDN - Array.sort ()
jahroy

1
โปรดยอมรับคำตอบของ @PramodVemulapalli ผู้ที่ได้รับการโหวตสูงในขณะนี้ถือว่าผิด!
Bergi

@jahroy: มันไม่เกี่ยวกับการบังคับประเภท แต่มันเกี่ยวกับข้อกำหนดสำหรับฟังก์ชันการเปรียบเทียบที่สอดคล้องกัน
Bergi

คำตอบ:


113

มันง่ายมาก:

var a = [[12, 'AAA'], [58, 'BBB'], [28, 'CCC'],[18, 'DDD']];

a.sort(sortFunction);

function sortFunction(a, b) {
    if (a[0] === b[0]) {
        return 0;
    }
    else {
        return (a[0] < b[0]) ? -1 : 1;
    }
}

ผมขอเชิญคุณอ่านเอกสาร

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

a.sort(compareSecondColumn);

function compareSecondColumn(a, b) {
    if (a[1] === b[1]) {
        return 0;
    }
    else {
        return (a[1] < b[1]) ? -1 : 1;
    }
}

4
โปรดทดสอบรหัสของคุณจริงๆ jsfiddle.net/DuR4B/2 . ตรงจากลิงก์เอกสารที่คุณโพสต์: "หากไม่มีการให้ CompareFunction องค์ประกอบต่างๆจะถูกจัดเรียงโดยการแปลงเป็นสตริงและเปรียบเทียบสตริงตามลำดับศัพท์ (" พจนานุกรม "หรือ" สมุดโทรศัพท์ "ไม่ใช่ตัวเลข) ตัวอย่างเช่น" 80 "จะมา ก่อน "9" ตามลำดับพจนานุกรม แต่ในการเรียงลำดับตัวเลข 9 จะมาก่อน 80 "
Ian

3
@ เอียน - คุณพูดถูก จุดดี. ฉันเดาว่าฉันตื่นเต้นมากที่ได้พิสูจน์ประเด็นเกี่ยวกับความเรียบง่าย ฉันทดสอบแล้ว แต่ไม่สมบูรณ์ ตอนนี้ฉันจะแก้ไข ... ฉันหวังว่าข้อมูลตัวอย่างจะพิสูจน์จุดของคุณก่อนที่ฉันจะทาไข่นั้นให้ทั่วใบหน้า!
jahroy

ฮ่าฮ่าฉันรู้ว่าฉันเกลียดเมื่อเรื่องแบบนั้นเกิดขึ้น ดูเหมือนถูกต้อง แต่มีบางอย่างเปลี่ยนแปลงภายในซึ่งไม่เป็นไปตามที่คาดไว้ Kinda เหมือนเปรียบเทียบสตริงหรือ< >อย่างไรก็ตามฉันชอบการอัปเดต :)
Ian

1
@ แอช - สถานที่ที่ดีที่สุดในการดูคือเอกสาร ฉันเหมือนเอกสารของ Mozilla ดังนั้นเมื่อผมมีคำถามเกี่ยวกับ JS ที่ทำงานฉันมักจะ google "MDN {{}} function_name. " ในกรณีนี้คำค้นหาจะเป็น"MDN Array.Sort"ซึ่งนำคุณมาที่นี่
jahroy

1
... ดังที่คุณจะเห็นในเอกสารประกอบเมธอด array.sort ()ใช้ฟังก์ชันเป็นอาร์กิวเมนต์ซึ่งเป็นเรื่องธรรมดาใน JavaScript Array.Sort ()วิธีการออกแบบในลักษณะที่จะรู้ว่าสิ่งที่จะทำอย่างไรกับฟังก์ชั่นผ่านไป: มันใช้มันเพื่อเปรียบเทียบองค์ประกอบของ นี่เป็นซอที่ง่อยจริงๆที่ฉันทำขึ้นเพื่อแสดงให้เห็นว่าคุณส่งผ่านฟังก์ชันเป็นข้อมูลอ้างอิงอย่างไร ... ขออภัยมันแย่มาก
jahroy

66

แนวทางที่ดีที่สุดคือใช้สิ่งต่อไปนี้เนื่องจากอาจมีค่าซ้ำกันในคอลัมน์แรก

var arr = [[12, 'AAA'], [12, 'BBB'], [12, 'CCC'],[28, 'DDD'], [18, 'CCC'],[12, 'DDD'],[18, 'CCC'],[28, 'DDD'],[28, 'DDD'],[58, 'BBB'],[68, 'BBB'],[78, 'BBB']];

arr.sort(function(a,b) {
    return a[0]-b[0]
});

นี่คือคำตอบที่ถูกต้องโดยคำนึงถึงตัวเลขทั้งสองหลักด้วย ขอบคุณ!
ชื่อเล่น

53

ลองดู

//WITH FIRST COLUMN
arr = arr.sort(function(a,b) {
    return a[0] - b[0];
});


//WITH SECOND COLUMN
arr = arr.sort(function(a,b) {
    return a[1] - b[1];
});

หมายเหตุ: คำตอบเดิมใช้มากกว่า (>) แทนเครื่องหมายลบ (-) ซึ่งเป็นความคิดเห็นที่อ้างถึงว่าไม่ถูกต้อง


8
8 โหวตวิธีแก้ปัญหาที่ผิดอย่างโจ่งแจ้ง? ฉันไม่อยากจะเชื่อเรื่องนี้เลย. โปรดอ่านเกี่ยวกับฟังก์ชันการเปรียบเทียบและทำความเข้าใจเมื่อจำเป็นต้องส่งคืนค่าลบ
Bergi

6
ตามที่ Bergi กล่าวไว้นี่ไม่ใช่วิธีแก้ปัญหาที่ถูกต้อง แม้ว่ามันอาจจะใช้ได้ผลในหลาย ๆ กรณี แต่ก็มีบางครั้งที่มันไม่ได้ผลตามที่คาดหวังและคุณจะเกาหัวทิ้งไว้ (มันเคยเกิดขึ้นกับฉันแล้ว) ปมของปัญหาคือฟังก์ชันเปรียบเทียบในโซลูชันนี้จะส่งคืนสถานะสองสถานะเท่านั้น (จริง / 1, เท็จ / 0) แต่ควรคืนค่าสามสถานะ (ศูนย์มากกว่าศูนย์และน้อยกว่าศูนย์)
thdoan

1
ไม่ได้ผลสำหรับฉัน @jahroy คือผู้ชายที่มีคำตอบที่ถูกต้อง
erdomester

หมายเหตุสำหรับผู้ที่อ่านความคิดเห็น: คำตอบได้รับการแก้ไขเมื่อวันที่ 5 มกราคมตอนนี้ถูกต้องแล้ว (ฟังก์ชันการเปรียบเทียบจะส่งคืนสถานะที่เป็นไปได้สามสถานะ)
marlar

@Bergi ขอบคุณที่ชี้ให้เห็น (สำหรับฉันมันทำงานไม่ถูกต้องใน IE11) และฉันไม่เข้าใจ (ทำไมมันถึงใช้งานได้ใน chrome) จนกว่าฉันจะเห็นความคิดเห็นของคุณ ขอบคุณ!
Alex Nevsky

12

ใช้ฟังก์ชันลูกศรและจัดเรียงตามฟิลด์สตริงที่สอง

var a = [[12, 'CCC'], [58, 'AAA'], [57, 'DDD'], [28, 'CCC'],[18, 'BBB']];
a.sort((a, b) => a[1].localeCompare(b[1]));
console.log(a)


10

หากคุณเป็นเหมือนฉันคุณจะไม่ต้องการเปลี่ยนดัชนีทุกครั้งที่คุณต้องการเปลี่ยนคอลัมน์ที่คุณจัดเรียง

function sortByColumn(a, colIndex){

    a.sort(sortFunction);

    function sortFunction(a, b) {
        if (a[colIndex] === b[colIndex]) {
            return 0;
        }
        else {
            return (a[colIndex] < b[colIndex]) ? -1 : 1;
        }
    }

    return a;
}

var sorted_a = sortByColumn(a, 2);

ฉันเพิ่งเห็นคำตอบของคุณหลังจากร่างคำตอบด้วยเหตุผลเดียวกันทั้งหมด - โดยมีข้อแตกต่างเล็กน้อย - ฉันส่งคืนฟังก์ชันเพื่อจัดเรียงโดยตรง
olamotte

3

ไม่มีอะไรพิเศษเพียงแค่ประหยัดค่าใช้จ่ายในการคืนค่าที่ดัชนีบางรายการจากอาร์เรย์

function sortByCol(arr, colIndex){
    arr.sort(sortFunction)
    function sortFunction(a, b) {
        a = a[colIndex]
        b = b[colIndex]
        return (a === b) ? 0 : (a < b) ? -1 : 1
    }
}
// Usage
var a = [[12, 'AAA'], [58, 'BBB'], [28, 'CCC'],[18, 'DDD']]
sortByCol(a, 0)
console.log(JSON.stringify(a))
// "[[12,"AAA"],[18,"DDD"],[28,"CCC"],[58,"BBB"]]"

คำตอบนี้แตกต่างจากของฉันที่นี่อย่างไร?
Charles Clayton

1
1. คุณกำลังใช้a[colIndex]อีกครั้งและอีกครั้ง a = a[colIndex]แต่ผมจับได้ที่นี่ มีประสิทธิภาพมากขึ้น 2. ฉันใช้รสชาติที่แตกต่างกันifทำให้สั้นลง 3. ฉันไม่ได้กลับมาarrเนื่องจากsortByColฟังก์ชันซึ่งหมายความว่าฟังก์ชันของฉันไม่สามารถใช้เพื่อสร้างข้อมูลอ้างอิงอื่นได้ หวังว่าจะช่วยได้!
Vikas Gautam

3

ในหนึ่งบรรทัด:

var cars = [
  {type:"Volvo", year:2016},
  {type:"Saab", year:2001},
  {type:"BMW", year:2010}
]


function myFunction() {
  return cars.sort((a, b)=> a.year - b.year)
}

3

หากคุณต้องการที่จะเรียงลำดับขึ้นอยู่กับคอลัมน์แรก (ซึ่งมีจำนวนค่า) แล้วลองนี้

arr.sort(function(a,b){
  return a[0]-b[0]
})

หากคุณต้องการจัดเรียงตามคอลัมน์ที่สอง (ซึ่งมีค่าสตริง ) ให้ลองทำดังนี้:

arr.sort(function(a,b){
  return a[1].charCodeAt(0)-b[1].charCodeAt(0)
})

ป.ล. สำหรับกรณีที่สองคุณต้องเปรียบเทียบระหว่างค่า ASCII

หวังว่านี่จะช่วยได้


0

เนื่องจาก usecase ของฉันเกี่ยวข้องกับคอลัมน์หลายสิบคอลัมน์ฉันจึงขยายคำตอบของ @jahroy เล็กน้อย (ยังเพิ่งตระหนักว่า @ charles-clayton ก็มีความคิดเดียวกัน)
ฉันส่งผ่านพารามิเตอร์ที่ต้องการจัดเรียงและฟังก์ชันการเรียงลำดับจะถูกกำหนดใหม่ด้วยดัชนีที่ต้องการเพื่อให้การเปรียบเทียบเกิดขึ้น

var ID_COLUMN=0
var URL_COLUMN=1

findings.sort(compareByColumnIndex(URL_COLUMN))

function compareByColumnIndex(index) {
  return function(a,b){
    if (a[index] === b[index]) {
        return 0;
    }
    else {
        return (a[index] < b[index]) ? -1 : 1;
    }
  }
}

0

เมื่อยืนอยู่บนไหล่ของ charles-clayton และ @ vikas-gautam ฉันได้เพิ่มการทดสอบสตริงซึ่งจำเป็นหากคอลัมน์มีสตริงเหมือนใน OP

return isNaN(a-b) ? (a === b) ? 0 : (a < b) ? -1 : 1 : a-b  ;

การทดสอบisNaN(a-b)จะพิจารณาว่าสตริงไม่สามารถบังคับเป็นตัวเลขได้หรือไม่ หากทำได้การa-bทดสอบก็ใช้ได้

โปรดทราบว่าการจัดเรียงคอลัมน์แบบคละประเภทจะให้ผลลัพธ์ที่สนุกสนานเสมอเนื่องจากการทดสอบความเท่าเทียมกันอย่างเข้มงวด(a === b)จะแสดงผลเท็จเสมอ ดู MDN ที่นี่

นี่คือสคริปต์ฉบับเต็มพร้อมการทดสอบ Logger - โดยใช้ Google Apps Script

function testSort(){

function sortByCol(arr, colIndex){
    arr.sort(sortFunction);
    function sortFunction(a, b) {
        a = a[colIndex];
        b = b[colIndex];
       return isNaN(a-b) ? (a === b) ? 0 : (a < b) ? -1 : 1 : a-b  ;  // test if text string - ie cannot be coerced to numbers.
       // Note that sorting a column of mixed types will always give an entertaining result as the strict equality test will always return false
       // see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Equality_comparisons_and_sameness

       }
}
// Usage
var a = [ [12,'12', 'AAA'],
          [12,'11', 'AAB'],
          [58,'120', 'CCC'],
          [28,'08', 'BBB'],
          [18,'80', 'DDD'],
        ]
    var arr1 = a.map(function (i){return i;}).sort();  // use map to ensure tests are not corrupted by a sort in-place.

    Logger.log("Original unsorted:\n     " + JSON.stringify(a));
    Logger.log("Vanilla sort:\n     " + JSON.stringify(arr1));
    sortByCol(a, 0);
    Logger.log("By col 0:\n     " + JSON.stringify(a));
    sortByCol(a, 1);
    Logger.log("By col 1:\n     " + JSON.stringify(a));
    sortByCol(a, 2);
    Logger.log("By col 2:\n     " + JSON.stringify(a));

/* vanilla sort returns " [
                            [12,"11","AAB"],
                            [12,"12","AAA"],
                            [18,"80","DDD"],
                            [28,"08","BBB"],
                            [58,"120","CCC"]
                          ]
   if col 0 then returns "[
                            [12,'12',"AAA"],
                            [12,'11', 'AAB'],
                            [18,'80',"DDD"],
                            [28,'08',"BBB"],
                            [58,'120',"CCC"]
                          ]"
   if col 1 then returns "[
                            [28,'08',"BBB"],
                            [12,'11', 'AAB'],
                            [12,'12',"AAA"],
                            [18,'80',"DDD"],
                            [58,'120',"CCC"],

                          ]"
   if col 2 then returns "[
                            [12,'12',"AAA"],
                            [12,'11', 'AAB'],
                            [28,'08',"BBB"],
                            [58,'120',"CCC"],
                            [18,'80',"DDD"],
                          ]"
*/

}

อัปเดตความสนใจที่เป็นไปได้ - 2 กรกฎาคม 2019 การเรียงลำดับเป็น "คงที่" อ่านได้ที่นี่ (ผ่าน Mathias BynensVerified @mathias) v8.dev/features/stable-sort
DeeKay789
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.