เป็นไปได้ไหมที่จะจัดเรียงวัตถุแผนที่ ES6


98

เป็นไปได้ไหมที่จะจัดเรียงรายการของวัตถุแผนที่ es6

var map = new Map();
map.set('2-1', foo);
map.set('0-1', bar);

ผลลัพธ์ใน:

map.entries = {
    0: {"2-1", foo },
    1: {"0-1", bar }
}

เป็นไปได้ไหมที่จะจัดเรียงรายการตามคีย์

map.entries = {
    0: {"0-1", bar },
    1: {"2-1", foo }
}

4
แผนที่จะไม่เรียงลำดับโดยเนื้อแท้ (ยกเว้นลำดับการแทรกซ้ำซึ่งต้องมีการเรียงลำดับแล้ว [ใหม่] เพิ่ม)
user2864740

1
จัดเรียงรายการเมื่อคุณวนซ้ำบนแผนที่ (เช่นเปลี่ยนเป็นอาร์เรย์)
Halcyon

คำตอบ:


140

ตามเอกสาร MDN:

วัตถุแผนที่วนซ้ำองค์ประกอบตามลำดับการแทรก

คุณสามารถทำได้ด้วยวิธีนี้:

var map = new Map();
map.set('2-1', "foo");
map.set('0-1', "bar");
map.set('3-1', "baz");

var mapAsc = new Map([...map.entries()].sort());

console.log(mapAsc)

ใช้.sort()จำไว้ว่าอาร์เรย์จะเรียงตามมูลค่าจุดรหัส Unicode อักขระแต่ละตัวตามการแปลงสตริงของแต่ละองค์ประกอบ จึง2-1, 0-1, 3-1จะเรียงได้ถูก.


7
คุณสามารถย่อฟังก์ชันนั้น (a, b) ให้สั้นลงเป็น: var mapAsc = new Map([...map.entries()].sort((a,b) => a[0] > b[0]));โดยใช้ฟังก์ชันลูกศร (แลมบ์ดา)
จิมมี่จันทรา

2
ในความเป็นจริงมัน acutally lexically เปรียบเทียบ2-1,fooการ0-1,barและ3-1,baz
Bergi


3
...จุดมีความสำคัญมิฉะนั้นคุณกำลังพยายามที่จะจัดเรียง MapIterator
muttonUp

2
หากคีย์แผนที่เป็นตัวเลขคุณจะได้ผลลัพธ์ที่ไม่ถูกต้องโดยมีตัวเลขเหมือน1e-9ใส่ไว้100ในแผนที่ที่เรียงลำดับ รหัสที่ใช้กับตัวเลข:new Map([...map.entries()].sort((e1, e2) => e1[0] - e2[0]))
cdalxndr

59

คำตอบสั้น ๆ

 new Map([...map].sort((a, b) => 
   // Some sort function comparing keys with a[0] b[0] or values with a[1] b[1]
   // Be sure to return -1 if lower and, if comparing values, return 0 if equal
 ))

ตัวอย่างเช่นการเปรียบเทียบสตริงค่าซึ่งสามารถเท่ากันได้เราส่งผ่านฟังก์ชันการจัดเรียงที่เข้าถึง [1] และมีเงื่อนไขเท่ากับที่ส่งคืน 0:

 new Map([...map].sort((a, b) => (a[1] > b[1] && 1) || (a[1] === b[1] ? 0 : -1)))

การเปรียบเทียบสตริงคีย์ซึ่งไม่สามารถเท่ากันได้ (คีย์สตริงที่เหมือนกันจะเขียนทับกัน) เราสามารถข้ามเงื่อนไขที่เท่าเทียมกันได้ อย่างไรก็ตามเราควรคืนค่า -1 อย่างชัดเจนเนื่องจากการส่งคืนค่าขี้เกียจa[0] > b[0]อย่างไม่ถูกต้องจะให้เท็จ (ถือว่าเป็น 0 คือเท่ากับ) เมื่อa[0] < b[0]:

 new Map([...map].sort((a, b) => a[0] > b[0] ? 1 : -1))

โดยละเอียดพร้อมตัวอย่าง

.entries()ใน[...map.entries()](ข้อเสนอแนะในหลายคำตอบ) เป็นซ้ำซ้อนอาจเพิ่มย้ำเป็นพิเศษของแผนที่เว้นแต่ JS เพิ่มประสิทธิภาพเครื่องยนต์ที่อยู่ห่างออกไปสำหรับคุณ

ในกรณีทดสอบง่ายๆคุณสามารถทำสิ่งที่คำถามถามได้ดังนี้

new Map([...map].sort())

... ซึ่งหากคีย์เป็นสตริงทั้งหมดให้เปรียบเทียบสตริงคีย์ - ค่าที่รวมด้วยเครื่องหมายจุลภาคและบีบบังคับเช่น'2-1,foo'และ'0-1,[object Object]'ส่งคืนแผนที่ใหม่พร้อมลำดับการแทรกใหม่:

หมายเหตุ: หากคุณเห็นเฉพาะ{}ในเอาต์พุตคอนโซลของ SO ให้ดูในคอนโซลเบราว์เซอร์จริงของคุณ

const map = new Map([
  ['2-1', 'foo'],
  ['0-1', { bar: 'bar' }],
  ['3-5', () => 'fuz'],
  ['3-2', [ 'baz' ]]
])

console.log(new Map([...map].sort()))

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

const map = new Map([
  ['2', '3,buh?'],
  ['2,1', 'foo'],
  ['0,1', { bar: 'bar' }],
  ['3,5', () => 'fuz'],
  ['3,2', [ 'baz' ]],
])

// Compares '2,3,buh?' with '2,1,foo'
// Therefore sorts ['2', '3,buh?'] ******AFTER****** ['2,1', 'foo']
console.log('Buh?', new Map([...map].sort()))

// Let's see exactly what each iteration is using as its comparator
for (const iteration of map) {
  console.log(iteration.toString())
}

ข้อบกพร่องเช่นนี้ยากที่จะแก้ไขข้อบกพร่อง - อย่าเสี่ยง!

หากคุณต้องการจัดเรียงคีย์หรือค่าควรเข้าถึงอย่างชัดเจนด้วยa[0]และb[0]ในฟังก์ชันการจัดเรียงเช่นนี้ โปรดทราบว่าเราควรกลับ-1และ1ก่อนและหลังไม่ใช่falseหรือ0เช่นเดียวกับดิบa[0] > b[0]เพราะถือว่าเท่ากับ:

const map = new Map([
  ['2,1', 'this is overwritten'],
  ['2,1', '0,1'],
  ['0,1', '2,1'],
  ['2,2', '3,5'],
  ['3,5', '2,1'],
  ['2', ',9,9']
])

// For keys, we don't need an equals case, because identical keys overwrite 
const sortStringKeys = (a, b) => a[0] > b[0] ? 1 : -1 

// For values, we do need an equals case
const sortStringValues = (a, b) => (a[1] > b[1] && 1) || (a[1] === b[1] ? 0 : -1)

console.log('By keys:', new Map([...map].sort(sortStringKeys)))
console.log('By values:', new Map([...map].sort(sortStringValues)))


11
คำตอบคืออะไรเราต้องแก้ไขกลไกการค้นพบ SO สิ่งดีๆนี้ไม่ควรหายไปที่นี่
serraosays

30

แปลงMapเป็นอาร์เรย์โดยใช้Array.fromจัดเรียงอาร์เรย์แปลงกลับเป็นMapเช่น

new Map(
  Array
    .from(eventsByDate)
    .sort((a, b) => {
      // a[0], b[0] is the key of the map
      return a[0] - b[0];
    })
)

1
[...map.values()].sort()ไม่ได้ผลสำหรับฉัน แต่Array.from(map.values()).sort()ทำ
Rob Juurlink

1
สิ่งนี้ช่วยฉันได้จริงหากไม่มี Array.from typescript ทำให้ฉันมีข้อผิดพลาดในการคอมไพล์
icSapper

7

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

var unsortedMap = new Map();
unsortedMap.set('2-1', 'foo');
unsortedMap.set('0-1', 'bar');

// Initialize your keys array
var keys = [];
// Initialize your sorted maps object
var sortedMap = new Map();

// Put keys in Array
unsortedMap.forEach(function callback(value, key, map) {
    keys.push(key);
});

// Sort keys array and go through them to put in and put them in sorted map
keys.sort().map(function(key) {
    sortedMap.set(key, unsortedMap.get(key));
});

// View your sorted map
console.log(sortedMap);

2
unsortedMap.keys()คีย์ไม่ได้เรียงลำดับสามารถกำหนดได้ง่ายๆโดยการใช้ นอกจากนี้ควรจะเป็นkeys.sort().map... keys.sort().forEach...
faintsignal

5

คุณสามารถแปลงเป็นอาร์เรย์และเรียกใช้วิธีการเรียงลำดับอาร์เรย์ได้:

[...map].sort(/* etc */);

3
และอะไร? คุณได้รับอาร์เรย์ไม่ใช่แผนที่หรือวัตถุ
กรีน

5
และคุณทำกุญแจ
หาย


3

วิธีหนึ่งคือรับอาร์เรย์รายการเรียงลำดับแล้วสร้างแผนที่ใหม่ด้วยอาร์เรย์ที่เรียงลำดับ:

let ar = [...myMap.entries()];
sortedArray = ar.sort();
sortedMap = new Map(sortedArray);

แต่ถ้าคุณไม่ต้องการสร้างออบเจ็กต์ใหม่ แต่ต้องการทำงานบนวัตถุเดียวกันคุณสามารถทำสิ่งนี้ได้:

// Get an array of the keys and sort them
let keys = [...myMap.keys()];
sortedKeys = keys.sort();

sortedKeys.forEach((key)=>{
  // Delete the element and set it again at the end
  const value = this.get(key);
  this.delete(key);
  this.set(key,value);
})

1

ข้อมูลโค้ดด้านล่างจะจัดเรียงแผนที่ตามคีย์และแมปคีย์กับอ็อบเจ็กต์คีย์ - ค่าอีกครั้ง ฉันใช้ฟังก์ชัน localeCompare เนื่องจากแผนที่ของฉันเป็น string-> string object map

var hash = {'x': 'xx', 't': 'tt', 'y': 'yy'};
Object.keys(hash).sort((a, b) => a.localeCompare(b)).map(function (i) {
            var o = {};
            o[i] = hash[i];
            return o;
        });

ผลลัพธ์: [{t:'tt'}, {x:'xx'}, {y: 'yy'}];


1

เท่าที่ฉันเห็นในขณะนี้ยังไม่สามารถจัดเรียงแผนที่ได้อย่างถูกต้อง

โซลูชันอื่น ๆ ที่ Map ถูกแปลงเป็นอาร์เรย์และจัดเรียงด้วยวิธีนี้มีจุดบกพร่องดังต่อไปนี้:

var a = new Map([[1, 2], [3,4]])
console.log(a);    // a = Map(2) {1 => 2, 3 => 4}

var b = a;
console.log(b);    // b = Map(2) {1 => 2, 3 => 4}

a = new Map();     // this is when the sorting happens
console.log(a, b); // a = Map(0) {}     b = Map(2) {1 => 2, 3 => 4}

การเรียงลำดับจะสร้างวัตถุใหม่และตัวชี้อื่น ๆ ทั้งหมดไปยังวัตถุที่ไม่ได้เรียงลำดับจะเสียหาย


1

ใช้เวลา 2 ชั่วโมงเพื่อดูรายละเอียด

โปรดทราบว่ามีคำตอบสำหรับคำถามอยู่แล้วที่https://stackoverflow.com/a/31159284/984471

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

  • ตัวอย่างเพิ่มเติมที่นี่: https://javascript.info/map-set
  • คุณสามารถคัดลอก - วางโค้ดด้านล่างลงในลิงค์ต่อไปนี้และแก้ไขสำหรับกรณีการใช้งานเฉพาะของคุณ: https://www.jdoodle.com/execute-nodejs-online/

.

let m1 = new Map();

m1.set(6,1); // key 6 is number and type is preserved (can be strings too)
m1.set(10,1);
m1.set(100,1);
m1.set(1,1);
console.log(m1);

// "string" sorted (even if keys are numbers) - default behaviour
let m2 = new Map( [...m1].sort() );
//      ...is destructuring into individual elements
//      then [] will catch elements in an array
//      then sort() sorts the array
//      since Map can take array as parameter to its constructor, a new Map is created
console.log('m2', m2);

// number sorted
let m3 = new Map([...m1].sort((a, b) => {
  if (a[0] > b[0]) return 1;
  if (a[0] == b[0]) return 0;
  if (a[0] < b[0]) return -1;
}));
console.log('m3', m3);

// Output
//    Map { 6 => 1, 10 => 1, 100 => 1, 1 => 1 }
// m2 Map { 1 => 1, 10 => 1, 100 => 1, 6 => 1 }
//           Note:  1,10,100,6  sorted as strings, default.
//           Note:  if the keys were string the sort behavior will be same as this
// m3 Map { 1 => 1, 6 => 1, 10 => 1, 100 => 1 }
//           Note:  1,6,10,100  sorted as number, looks correct for number keys

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


0

บางทีอาจเป็นตัวอย่างที่เป็นจริงมากขึ้นเกี่ยวกับการไม่จัดเรียงวัตถุแผนที่ แต่เป็นการเตรียมการจัดเรียงไว้ล่วงหน้าก่อนทำแผนที่ ไวยากรณ์จะค่อนข้างกะทัดรัดหากคุณทำเช่นนี้ คุณสามารถใช้การจัดเรียงก่อนฟังก์ชันแผนที่เช่นนี้ด้วยฟังก์ชันการจัดเรียงก่อนแผนที่ (ตัวอย่างจากแอป React ฉันกำลังทำงานโดยใช้ไวยากรณ์ JSX)

ทำเครื่องหมายที่นี่ฉันกำหนดฟังก์ชันการเรียงลำดับภายในโดยใช้ฟังก์ชันลูกศรที่ส่งกลับค่า -1 หากมีขนาดเล็กกว่าและจัดเรียง 0 ในคุณสมบัติของวัตถุ Javascript ในอาร์เรย์ที่ฉันได้รับจาก API

report.ProcedureCodes.sort((a, b) => a.NumericalOrder < b.NumericalOrder ? -1 : 0).map((item, i) =>
                        <TableRow key={i}>

                            <TableCell>{item.Code}</TableCell>
                            <TableCell>{item.Text}</TableCell>
                            {/* <TableCell>{item.NumericalOrder}</TableCell> */}
                        </TableRow>
                    )

-2
let map = new Map();
map.set('2-1', "foo");
map.set('0-1', "bar");
map.set('3-1', "baz");
let mapAsc = new Map([...map.entries()].sort());
console.log(mapAsc);

// Map(3) {"0-1" => "bar", "2-1" => "foo", "3-1" => "baz"}

3
แม้ว่าสิ่งนี้อาจตอบคำถามของผู้เขียน แต่ก็ขาดคำอธิบายและลิงก์ไปยังเอกสารประกอบ ข้อมูลโค้ดดิบจะไม่เป็นประโยชน์มากนักหากไม่มีวลีบางอย่างอยู่รอบ ๆ โปรดแก้ไขคำตอบของคุณ
hellow

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