Javascript เรียงลำดับอาร์เรย์ตามสองฟิลด์


92
grouperArray.sort(function (a, b) {
    var aSize = a.gsize;
    var bSize = b.gsize;
    var aLow = a.glow;
    var bLow = b.glow;
    console.log(aLow + " | " + bLow);      
    return (aSize < bSize) ? -1 : (aSize > bSize) ? 1 : 0;
});

ดังนั้นโค้ดด้านบนจึงจัดเรียงอาร์เรย์ตามขนาด - เล็กที่สุดไปหาใหญ่ที่สุด มันใช้งานได้ดี แต่ถ้า gsize เท่ากันฉันอยากให้เรียงตามเรืองแสง

ขอบคุณ.


ฟังก์ชัน sort ตอบสนองต่อผลลัพธ์ที่เป็นบวกลบหรือศูนย์ ดังนั้นคุณสามารถเขียน: "return aSize - bSize" มันจะเป็นรหัสที่ง่ายและอ่านได้มากขึ้น

คำตอบ:


112
grouperArray.sort(function (a, b) {
    var aSize = a.gsize;
    var bSize = b.gsize;
    var aLow = a.glow;
    var bLow = b.glow;
    console.log(aLow + " | " + bLow);

    if(aSize == bSize)
    {
        return (aLow < bLow) ? -1 : (aLow > bLow) ? 1 : 0;
    }
    else
    {
        return (aSize < bSize) ? -1 : 1;
    }
});

นี้เพื่อให้รัดกุมมากขึ้นโดยใช้ไวยากรณ์ลูกศรโดยไม่ต้อง resorting เทคนิคที่ไม่ชัดเจนที่แสดงให้เห็นในคำตอบอื่น ๆgrouperArray.sort((a, b) => a.gsize == b.gsize ? a.glow - b.glow : a.gsize - b.gsize: ==ที่จะทำให้รหัสง่ายต่อการเข้าใจเราให้ชัดเจนสำหรับการทดสอบ
ToolmakerSteve

171
grouperArray.sort(function (a, b) {   
    return a.gsize - b.gsize || a.glow - b.glow;
});

รุ่นที่สั้นกว่า


เกรียนสุด ๆ ! ช่วยฉันใส่วิธีแก้ปัญหาที่ซับซ้อนมากขึ้นด้วยกัน .. stackoverflow.com/questions/6101475/…
Joseph Poirier

3
สวยและสะอาด! สิ่งเดียวที่ใช้ได้กับตัวเลขเท่านั้น
Afanasii Kurakin

อธิบายตรรกะตรงนี้ได้ไหม!. มันได้ผลสำหรับฉันsort an array with a key's value firstแล้วsort the result with another key's value
KTM

1
@KTM ตรรกะจะเป็นดังนี้: ถ้าทั้งสองขนาดเท่ากันส่วนแรกของเงื่อนไขจะเท่ากับ 0 ซึ่งถือว่าเป็นเท็จและส่วนที่สองของเงื่อนไขจะถูกดำเนินการ
Scalpweb

@Scalpweb ใช่ :) ดังนั้นการทำงานนี้จะจัดเรียงอาร์เรย์ด้วยคีย์จำนวนเท่าใดก็ได้ทีละคีย์ใช่ไหม! เคล็ดลับ
ดีๆ

36
grouperArray.sort((a, b) => a.gsize - b.gsize || a.glow - b.glow);

เวอร์ชันที่สั้นกว่าโดยใช้ไวยากรณ์ของลูกศร!


3
กระชับและยืดได้เป๊ะสุด!
Laurent

1
ยิ่งสั้นกว่านั้นจงใช้ช่องว่าง:grouperArray.sort((a,b)=>a.gsize-b.gsize||a.glow-b.glow);
Captain Fantastic

หากคุณต้องการเข้าใจว่าทำไมถึงได้ผลคุณอาจต้องการดู medium.com/@safareli/pss-ordering-is-a-monoid-61a4029387e
Safareli

14

ฉันรู้ว่ามีคนถามมานานแล้ว แต่ฉันคิดว่าจะเพิ่มวิธีแก้ปัญหาของฉัน

ฟังก์ชันนี้จะสร้างวิธีการเรียงลำดับแบบไดนามิก เพียงระบุชื่อคุณสมบัติย่อยที่เรียงลำดับได้แต่ละชื่อโดยนำหน้าด้วย +/- เพื่อระบุลำดับจากน้อยไปมากหรือมากไปหาน้อย ใช้ซ้ำได้มากและไม่จำเป็นต้องรู้อะไรเกี่ยวกับโครงสร้างข้อมูลที่คุณรวมเข้าด้วยกัน สามารถพิสูจน์ได้ แต่ดูเหมือนไม่จำเป็น

function getSortMethod(){
    var _args = Array.prototype.slice.call(arguments);
    return function(a, b){
        for(var x in _args){
            var ax = a[_args[x].substring(1)];
            var bx = b[_args[x].substring(1)];
            var cx;

            ax = typeof ax == "string" ? ax.toLowerCase() : ax / 1;
            bx = typeof bx == "string" ? bx.toLowerCase() : bx / 1;

            if(_args[x].substring(0,1) == "-"){cx = ax; ax = bx; bx = cx;}
            if(ax != bx){return ax < bx ? -1 : 1;}
        }
    }
}

ตัวอย่างการใช้งาน:

items.sort (getSortMethod ('- ราคา', '+ ลำดับความสำคัญ', '+ ชื่อ'));

นี้จะจัดเรียงitemsกับต่ำสุดครั้งแรกที่มีความสัมพันธ์ไปรายการด้วยสูงสุดprice priorityความสัมพันธ์เพิ่มเติมถูกทำลายโดยรายการname

โดยที่รายการเป็นอาร์เรย์เช่น:

var items = [
    { name: "z - test item", price: "99.99", priority: 0, reviews: 309, rating: 2 },
    { name: "z - test item", price: "1.99", priority: 0, reviews: 11, rating: 0.5 },
    { name: "y - test item", price: "99.99", priority: 1, reviews: 99, rating: 1 },
    { name: "y - test item", price: "0", priority: 1, reviews: 394, rating: 3.5 },
    { name: "x - test item", price: "0", priority: 2, reviews: 249, rating: 0.5 } ...
];

การสาธิตสด: http://gregtaff.com/misc/multi_field_sort/

แก้ไข: แก้ไขปัญหาเกี่ยวกับ Chrome


นี่เป็นสิ่งที่ยอดเยี่ยม
Azure

อัจฉริยะตอบ!
Marius

สำหรับ typescript (เพื่อไม่ได้รับ an error TS2554: Expected 0 arguments, but got ..) ให้ใช้ไวยากรณ์ที่นี่: stackoverflow.com/a/4116634/5287221
Chananel P

6

ฉันคาดหวังว่าตัวดำเนินการternary((aSize < bSize) ? -1 : (aSize > bSize) ? 1 : 0;)มีคุณสับสน คุณควรตรวจสอบลิงก์เพื่อทำความเข้าใจให้ดีขึ้น

ก่อนหน้านี้รหัสของคุณจะเต็มไปหมดถ้า / else

grouperArray.sort(function (a, b) {
    if (a.gsize < b.gsize)
    {
        return -1;
    }
    else if (a.gsize > b.gsize)
    {
        return 1;
    }
    else
    {
        if (a.glow < b.glow)
        {
            return -1;
        }
        else if (a.glow > b.glow)
        {
            return 1;
        }
        return 0;
    }
});

6

นี่คือการใช้งานสำหรับผู้ที่อาจต้องการบางสิ่งที่ทั่วไปมากขึ้นซึ่งสามารถใช้ได้กับฟิลด์จำนวนเท่าใดก็ได้

Array.prototype.sortBy = function (propertyName, sortDirection) {

    var sortArguments = arguments;
    this.sort(function (objA, objB) {

        var result = 0;
        for (var argIndex = 0; argIndex < sortArguments.length && result === 0; argIndex += 2) {

            var propertyName = sortArguments[argIndex];
            result = (objA[propertyName] < objB[propertyName]) ? -1 : (objA[propertyName] > objB[propertyName]) ? 1 : 0;

            //Reverse if sort order is false (DESC)
            result *= !sortArguments[argIndex + 1] ? 1 : -1;
        }
        return result;
    });

}

โดยทั่วไปคุณสามารถระบุชื่อคุณสมบัติ / ทิศทางการจัดเรียงจำนวนเท่าใดก็ได้:

var arr = [{
  LastName: "Doe",
  FirstName: "John",
  Age: 28
}, {
  LastName: "Doe",
  FirstName: "Jane",
  Age: 28
}, {
  LastName: "Foo",
  FirstName: "John",
  Age: 30
}];

arr.sortBy("LastName", true, "FirstName", true, "Age", false);
//Will return Jane Doe / John Doe / John Foo

arr.sortBy("Age", false, "LastName", true, "FirstName", false);
//Will return John Foo / John Doe / Jane Doe

3
grouperArray.sort(function (a, b) {
  var aSize = a.gsize;
  var bSize = b.gsize;
  var aLow = a.glow;
  var bLow = b.glow;
  console.log(aLow + " | " + bLow);      
  return (aSize < bSize) ? -1 : (aSize > bSize) ? 1 : ( (aLow < bLow ) ? -1 : (aLow > bLow ) ? 1 : 0 );
});


3

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

sortMultiCompare = (a, b, sorts) => {
    let select = sorts[0].select
    let order = sorts[0].order
    if (a[select] < b[select]) {
        return order == 'ascending' ? -1 : 1
    } 
    if (a[select] > b[select]) {
        return order == 'ascending' ? 1 : -1
    }
    if(sorts.length > 1) {
        let remainingSorts = sorts.slice(1)
        return this.sortMultiCompare(a, b, remainingSorts)
    }
    return 0
}

sortResults = (results, sorts) => {
    return results.sort((a, b) => {
        return this.sortMultiCompare(a, b, sorts)
    })
}

// example inputs
const results = [
    {
        "LastName": "Doe",
        "FirstName": "John",
        "MiddleName": "Bill"
    },
    {
        "LastName": "Doe",
        "FirstName": "Jane",
        "MiddleName": "Bill"
    },
    {
        "LastName": "Johnson",
        "FirstName": "Kevin",
        "MiddleName": "Bill"
    }
]

const sorts = [
    {
        "select": "LastName",
        "order": "ascending"
    },
    {
        "select": "FirstName",
        "order": "ascending"
    },
    {
        "select": "MiddleName",
        "order": "ascending"
    }    
]

// call the function like this:
let sortedResults = sortResults(results, sorts)

2

วิธีแบบไดนามิกในการทำเช่นนั้นด้วยปุ่มหลายปุ่ม:

  • กรองค่าที่ไม่ซ้ำกันจากแต่ละ col / key ของการจัดเรียง
  • เรียงลำดับหรือย้อนกลับ
  • เพิ่ม zeropad ความกว้างของน้ำหนักสำหรับแต่ละออบเจ็กต์ตามค่าของคีย์ indexOf (value)
  • จัดเรียงโดยใช้ตุ้มน้ำหนักแบบ caclutated

ใส่คำอธิบายภาพที่นี่

Object.defineProperty(Array.prototype, 'orderBy', {
value: function(sorts) { 
    sorts.map(sort => {            
        sort.uniques = Array.from(
            new Set(this.map(obj => obj[sort.key]))
        );

        sort.uniques = sort.uniques.sort((a, b) => {
            if (typeof a == 'string') {
                return sort.inverse ? b.localeCompare(a) : a.localeCompare(b);
            }
            else if (typeof a == 'number') {
                return sort.inverse ? (a < b) : (a > b ? 1 : 0);
            }
            else if (typeof a == 'boolean') {
                let x = sort.inverse ? (a === b) ? 0 : a? -1 : 1 : (a === b) ? 0 : a? 1 : -1;
                return x;
            }
            return 0;
        });
    });

    const weightOfObject = (obj) => {
        let weight = "";
        sorts.map(sort => {
            let zeropad = `${sort.uniques.length}`.length;
            weight += sort.uniques.indexOf(obj[sort.key]).toString().padStart(zeropad, '0');
        });
        //obj.weight = weight; // if you need to see weights
        return weight;
    }

    this.sort((a, b) => {
        return weightOfObject(a).localeCompare( weightOfObject(b) );
    });

    return this;
}
});

ใช้:

// works with string, number and boolean
let sortered = your_array.orderBy([
    {key: "type", inverse: false}, 
    {key: "title", inverse: false},
    {key: "spot", inverse: false},
    {key: "internal", inverse: true}
]);

ใส่คำอธิบายภาพที่นี่


1

นี่คือสิ่งที่ฉันใช้

function sort(a, b) {
    var _a = "".concat(a.size, a.glow);
    var _b = "".concat(b.size, b.glow);
    return _a < _b;
}

เชื่อมสองรายการเป็นสตริงและจะจัดเรียงตามค่าสตริง หากคุณต้องการคุณสามารถตัด _a และ _b ด้วย parseInt เพื่อเปรียบเทียบเป็นตัวเลขถ้าคุณรู้ว่ามันจะเป็นตัวเลข


1

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

ตัวอย่างข้อมูลอินพุต ( id2คือคีย์การเรียงลำดับความสำคัญ):

const arr = [
    {id: 1},
    {id: 2, id2: 3},
    {id: 4},
    {id: 3},
    {id: 10, id2: 2},
    {id: 7},
    {id: 6, id2: 1},
    {id: 5},
    {id: 9, id2: 2},
    {id: 8},
];

และผลลัพธ์ควรเป็น:

[ { id: 6, id2: 1 },
  { id: 9, id2: 2 },
  { id: 10, id2: 2 },
  { id: 2, id2: 3 },
  { id: 1 },
  { id: 3 },
  { id: 4 },
  { id: 5 },
  { id: 7 },
  { id: 8 } ]

ฟังก์ชันตัวเปรียบเทียบจะเป็นดังนี้:

arr.sort((a,b) => {
  if(a.id2 || b.id2) {
    if(a.id2 && b.id2) {
      if(a.id2 === b.id2) {
        return a.id - b.id;
      }
      return a.id2 - b.id2;
    }
    return a.id2 ? -1 : 1;
  }
  return a.id - b.id
});

PS ในกรณีที่.idของ.id2typeofสามารถเป็นศูนย์พิจารณาถึงการใช้



0
grouperArray.sort(function (a, b) {
    var aSize = a.gsize;
    var bSize = b.gsize;
    if (aSize !== aSize)
        return aSize - bSize;
    return a.glow - b.glow;
});

ไม่ได้ทดสอบ แต่ฉันคิดว่าน่าจะใช้ได้


0

ในกรณีของฉันฉันเรียงลำดับรายการแจ้งเตือนตามพารามิเตอร์ 'สำคัญ' และตาม 'วันที่'

  • ขั้นตอนที่ 1: ฉันกรองการแจ้งเตือนตาม 'สำคัญ' และไม่สำคัญ

    let importantNotifications = notifications.filter(
            (notification) => notification.isImportant);
    
      let unImportantNotifications = notifications.filter(
            (notification) => !notification.isImportant);
    
  • ขั้นตอนที่ 2: ฉันจัดเรียงตามวันที่

      sortByDate = (notifications) => {
      return notifications.sort((notificationOne, notificationTwo) => {
        return notificationOne.date - notificationTwo.date;
      });
    };
    
  • ขั้นตอนที่ 3: รวมเข้าด้วยกัน

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