วิธีการเรียงลำดับค่าแผนที่ตามคีย์ใน Java?


361

ฉันมีแผนที่ที่มีสตริงสำหรับทั้งกุญแจและค่า

ข้อมูลเป็นดังนี้:

"question1", "1"
"question9", "1"
"question2", "4"
"question5", "2"

ฉันต้องการเรียงลำดับแผนที่ตามคีย์ของมัน ดังนั้นในที่สุดฉันจะมีquestion1, question2, question3.... และอื่น ๆ


ในที่สุดฉันพยายามดึงสองสายออกจากแผนที่นี้

  • สตริงแรก: คำถาม (ตามลำดับ 1 ..10)
  • สตริงที่สอง: คำตอบ (ในลำดับเดียวกันกับคำถาม)

ตอนนี้ฉันมีดังต่อไปนี้:

Iterator it = paramMap.entrySet().iterator();
while (it.hasNext()) {
    Map.Entry pairs = (Map.Entry) it.next();
    questionAnswers += pairs.getKey() + ",";
}

นี่ทำให้ฉันมีคำถามในสตริง แต่พวกเขาไม่ได้อยู่ในลำดับ

คำตอบ:


612

คำตอบสั้น ๆ

TreeMapการใช้งาน นี่คือสิ่งที่มันต้องการ

หากแผนที่นี้ผ่านให้คุณและคุณไม่สามารถระบุประเภทได้คุณสามารถทำสิ่งต่อไปนี้:

SortedSet<String> keys = new TreeSet<>(map.keySet());
for (String key : keys) { 
   String value = map.get(key);
   // do something
}

สิ่งนี้จะวนซ้ำทั่วทั้งแผนที่ตามลำดับคีย์


คำตอบอีกต่อไป

เทคนิคคุณสามารถใช้สิ่งที่ดำเนินการSortedMapแต่ยกเว้นกรณีที่หายากจำนวนนี้TreeMapเช่นเดียวกับที่ใช้ดำเนินการมักจะมีจำนวน MapHashMap

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

// placed inline for the demonstration, but doesn't have to be a lambda expression
Comparator<Foo> comparator = (Foo o1, Foo o2) -> {
        ...
    }

SortedSet<Foo> keys = new TreeSet<>(comparator);
keys.addAll(map.keySet());

จำได้ว่าเมื่อใช้TreeMapหรือTreeSetว่ามันจะมีลักษณะการทำงานที่แตกต่างกันกว่าหรือHashMap HashSetพูดประมาณว่าการดำเนินงานพบหรือใส่องค์ประกอบจะไปจากO (1)เพื่อO (เข้าสู่ระบบ (N))

ใน a การHashMapย้ายจาก 1,000 รายการไปยัง 10,000 ไม่ได้ส่งผลกระทบต่อเวลาของคุณในการค้นหาองค์ประกอบ แต่สำหรับTreeMapการค้นหาจะช้าลงประมาณ 3 เท่า (สมมติว่า Log 2 ) การย้ายจาก 1,000 เป็น 100,000 จะช้าลงประมาณ 6 เท่าสำหรับการค้นหาองค์ประกอบทั้งหมด


ฉันพยายามใช้ Treemap และจัดเรียงคีย์สตริงตามความยาว ฉันพบว่าฉันได้รับผลลัพธ์การดึงข้อมูลที่ไม่สอดคล้องกัน เห็นได้ชัดว่าเนื่องจาก TreeMap พิจารณาผลการเปรียบเทียบของ 0 เป็น "เท่ากับ" ไม่แน่ใจว่าจะใช้งานอย่างไรในกรณีนี้
Marc

1
comparTo () ผลจาก 0 คือ 'เท่ากับ' หากคุณเขียนตัวเปรียบเทียบที่เรียงตามความยาวสตริงคุณจะต้องส่งคืนค่าบวกหรือค่าลบโดยพิจารณาจากสตริงที่ยาวกว่าและส่งคืนค่า 0 หากทั้งสองสตริงมีความยาวเท่ากัน ถ้า a และ b เป็นสตริงคุณสามารถทำสิ่งนี้ได้เช่น `return a.length () - b.length () '(หรือย้อนกลับค่าถ้าคุณต้องการเรียงในทิศทางอื่น)
Jherico

สวัสดีทุกคนถ้าเขา / เธอต้องการที่จะสั่งซื้อแผนที่โดยใช้ปุ่มซึ่งที่นี่คือ 1,2,3,4 ลำดับการแทรกคืออะไร .... ทำไมเราไม่ใช้ LinkedHashSet เราแค่ใส่คำถามทีละตัวและมันก็ได้รับคำสั่งจากคำสั่งของการแทรก มีอะไรบ้างที่ช่วยฉันออกมาได้?
Karoly

@Karoly LinkedHashSet จะทำงานเพื่อดึงองค์ประกอบตามลำดับที่คุณแทรก สิ่งที่ OP ต้องการคือการดึงองค์ประกอบในการเรียงลำดับที่กำหนดไว้ล่วงหน้าโดยไม่คำนึงถึงลำดับการแทรก
David Berry

@ cricket_007 รหัสนี้แสดงให้เห็นถึงวิธีการทำซ้ำข้ามปุ่มเหล่านั้นสำหรับแผนที่ที่ยังไม่ได้จัดเรียง
Jherico

137

สมมติว่า TreeMap ไม่ดีสำหรับคุณ (และสมมติว่าคุณไม่สามารถใช้ยาสามัญได้):

List sortedKeys=new ArrayList(yourMap.keySet());
Collections.sort(sortedKeys);
// Do what you need with sortedKeys.

3
ขอบคุณ! ฉันต้องการทำสิ่งนี้เนื่องจากกุญแจของฉันเป็นแบบที่ซับซ้อน
Ross Hambrick

3
นี่จะเรียงลำดับรายการคีย์ แต่จะไม่เรียงลำดับแผนที่ตามคีย์ ฉันกำลังมองหาวิธีจัดเรียงแผนที่ตามคีย์และหาทางด้วย ฉันจะต้องลองกับ TreeMap ฉันเดา :)
Crenguta S

55

การใช้TreeMapแผนที่คุณสามารถเรียงลำดับ

Map<String, String> map = new HashMap<>();        
Map<String, String> treeMap = new TreeMap<>(map);
for (String str : treeMap.keySet()) {
    System.out.println(str);
}

1
แผนที่ <String, List <String>> treeMap = TreeMap ใหม่ <String, List <String>> (printHashMap); สำหรับ (String str: treeMap.keySet ()) {System.out.println (str + "" + treeMap.get (str)); }
vikramvi

37

ใช้TreeMap !


31
+1 - ไม่คล่องแคล่วพอที่จะเอาชนะ Jherico, Jon แต่ก็ยังค่อนข้างดี 8)
duffymo

ฉันไม่ทราบว่า Java :-( ใช้งานได้ 100% ง่ายกว่าโซลูชันที่น่ากลัวใด ๆ ที่ฉันได้รับ
peterchaula

36

หากคุณมีแผนที่อยู่แล้วและต้องการที่จะเรียงลำดับบนปุ่มใช้:

Map<String, String> treeMap = new TreeMap<String, String>(yourMap);

ตัวอย่างการทำงานที่สมบูรณ์:

import java.util.HashMap;
import java.util.Set;
import java.util.Map;
import java.util.TreeMap;
import java.util.Iterator;

class SortOnKey {

public static void main(String[] args) {
   HashMap<String,String> hm = new HashMap<String,String>();
   hm.put("3","three");
   hm.put("1","one");
   hm.put("4","four");
   hm.put("2","two");
   printMap(hm);
   Map<String, String> treeMap = new TreeMap<String, String>(hm);
   printMap(treeMap);
}//main

public static void printMap(Map<String,String> map) {
    Set s = map.entrySet();
    Iterator it = s.iterator();
    while ( it.hasNext() ) {
       Map.Entry entry = (Map.Entry) it.next();
       String key = (String) entry.getKey();
       String value = (String) entry.getValue();
       System.out.println(key + " => " + value);
    }//while
    System.out.println("========================");
}//printMap

}//class

36

เพียงแค่ใช้ TreeMap

new TreeMap<String, String>(unsortMap);

โปรดระวังว่า TreeMap นั้นเรียงลำดับตาม 'ปุ่ม' ตามธรรมชาติของมัน


19

คุณไม่สามารถใช้งานได้TreeMapในJava 8เราสามารถใช้วิธีtoMap ()Collectorsซึ่งใช้พารามิเตอร์ต่อไปนี้:

  • keymapper : ฟังก์ชั่นการทำแผนที่เพื่อผลิตกุญแจ
  • valueemapper : ฟังก์ชั่นการทำแผนที่ในการผลิตค่า
  • mergeFunction : ฟังก์ชันการผสานที่ใช้เพื่อแก้ไขการชนกันระหว่างค่าที่เกี่ยวข้องกับคีย์เดียวกัน
  • mapSupplier : ฟังก์ชันที่ส่งคืนแผนที่ใหม่ที่ว่างซึ่งจะแทรกผลลัพธ์

ตัวอย่าง Java 8

Map<String,String> sample = new HashMap<>();  // push some values to map  
Map<String, String> newMapSortedByKey = sample.entrySet().stream()
                    .sorted(Map.Entry.<String,String>comparingByKey().reversed())
                    .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e1, LinkedHashMap::new));
Map<String, String> newMapSortedByValue = sample.entrySet().stream()
                        .sorted(Map.Entry.<String,String>comparingByValue().reversed())
                        .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (e1,e2) -> e1, LinkedHashMap::new));

เราสามารถปรับเปลี่ยนตัวอย่างเพื่อใช้เครื่องมือเปรียบเทียบแบบกำหนดเองและจัดเรียงตามคีย์เป็น:

Map<String, String> newMapSortedByKey = sample.entrySet().stream()
                .sorted((e1,e2) -> e1.getKey().compareTo(e2.getKey()))
                .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (e1,e2) -> e1, LinkedHashMap::new));

ใช้ได้กับ Android ที่มี Api 24 ขึ้นไปเท่านั้น
Tina

9

ใช้Java 8:

Map<String, Integer> sortedMap = unsortMap.entrySet().stream()
            .sorted(Map.Entry.comparingByKey())
            .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue,
                    (oldValue, newValue) -> oldValue, LinkedHashMap::new));

5

รหัสนี้สามารถเรียงลำดับการแมปคีย์ - ค่าได้ทั้งในการสั่งซื้อเช่นจากน้อยไปมากและจากมากไปน้อย

<K, V extends Comparable<V>> Map<K, V> sortByValues
     (final Map<K, V> map, int ascending)
{
     Comparator<K> valueComparator =  new Comparator<K>() {         
        private int ascending;
        public int compare(K k1, K k2) {
            int compare = map.get(k2).compareTo(map.get(k1));
            if (compare == 0) return 1;
            else return ascending*compare;
        }
        public Comparator<K> setParam(int ascending)
        {
            this.ascending = ascending;
            return this;
        }
    }.setParam(ascending);

    Map<K, V> sortedByValues = new TreeMap<K, V>(valueComparator);
    sortedByValues.putAll(map);
    return sortedByValues;
}

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

Map<Integer,Double> recommWarrVals = new HashMap<Integer,Double>();
recommWarrVals = sortByValues(recommWarrVals, 1);  // Ascending order
recommWarrVals = sortByValues(recommWarrVals,-1);  // Descending order

5

ใน Java 8

การเรียงลำดับMap<K, V>โดยคีย์ใส่กุญแจเป็นList<K>:

List<K> result = map.keySet().stream().sorted().collect(Collectors.toList());

หากต้องการเรียงลำดับMap<K, V>ตามคีย์ให้ป้อนรายการในList<Map.Entry<K, V>>:

List<Map.Entry<K, V>> result =
    map.entrySet()
       .stream()
       .sorted(Map.Entry.comparingByKey())
       .collect(Collectors.toList());

สุดท้าย แต่ไม่ท้ายสุด: เพื่อเรียงลำดับสตริงในลักษณะที่มีความอ่อนไหว - ใช้คลาสCollator (ตัวเปรียบเทียบ)

Collator collator = Collator.getInstance(Locale.US);
collator.setStrength(Collator.PRIMARY); // case insensitive collator

List<Map.Entry<String, String>> result =
    map.entrySet()
       .stream()
       .sorted(Map.Entry.comparingByKey(collator))
       .collect(Collectors.toList());


1

ใน Java 8 คุณสามารถใช้. stream (). sort ():

myMap.keySet().stream().sorted().forEach(key -> {
        String value = myMap.get(key);

        System.out.println("key: " + key);
        System.out.println("value: " + value);
    }
);

0

นอกจากนี้เรายังสามารถเรียงลำดับคีย์โดยใช้วิธี Arrays.sort

Map<String, String> map = new HashMap<String, String>();
Object[] objArr = new Object[map.size()];
for (int i = 0; i < map.size(); i++) {
objArr[i] = map.get(i);
}
Arrays.sort(objArr);
for (Object str : objArr) {
System.out.println(str);
}

นี่คือการเรียงลำดับตามค่าและไม่ใช่กุญแจ
raaj

0

ในกรณีที่คุณไม่ต้องการใช้ TreeMap

public static Map<Integer, Integer> sortByKey(Map<Integer, Integer> map) {
    List<Map.Entry<Integer, Integer>> list = new ArrayList<>(map.entrySet());
    list.sort(Comparator.comparingInt(Map.Entry::getKey));
    Map<Integer, Integer> sortedMap = new HashMap<>();
    list.forEach(sortedMap.put(e.getKey(), e.getValue()));
    return sortedMap;
}

นอกจากนี้ในกรณีที่คุณต้องการที่จะค้าหาแผนที่ของคุณบนพื้นฐานของการvaluesเป็นเพียงแค่การเปลี่ยนแปลงMap.Entry::getKeyไปMap.Entry::getValue


สิ่งนี้เกิดขึ้นในบันทึกการตรวจสอบของฉัน มีคนพยายามแก้ไขข้อผิดพลาดบางอย่างด้วยชื่อตัวแปร (แต่ล้มเหลว) ดังนั้นฉันแก้ไขได้อย่างถูกต้องอย่างไรก็ตามคำตอบนี้เป็นเพียงพื้นฐานที่ผิด ลำดับที่คุณเพิ่มค่าให้กับ HashMap นั้นไม่เกี่ยวข้อง แผนที่ไม่มีคำสั่งซื้อ stackoverflow.com/questions/10710193/…
aepryus
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.