Bagaimana cara mengurutkan nilai peta dengan kunci di Jawa

362

Saya memiliki Peta yang memiliki string untuk kunci dan nilai.

Data seperti berikut:

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

Saya ingin mengurutkan peta berdasarkan kuncinya. Jadi, pada akhirnya, saya akan question1, question2, question3.... dan seterusnya.


Akhirnya, saya mencoba mengeluarkan dua string dari Peta ini.

  • String Pertama: Pertanyaan (dalam urutan 1 ..10)
  • String Kedua: Jawaban (dalam urutan yang sama dengan pertanyaan)

Saat ini saya memiliki yang berikut:

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

Ini membuat saya pertanyaan dalam sebuah string tetapi mereka tidak berurutan.

n00bstackie
sumber

Jawaban:

613

Jawaban singkat

Gunakan a TreeMap. Ini tepatnya untuk apa.

Jika peta ini diteruskan kepada Anda dan Anda tidak dapat menentukan jenisnya, maka Anda dapat melakukan hal berikut:

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

Ini akan beralih di seluruh peta dalam urutan alami tombol.


Jawaban yang lebih panjang

Secara teknis, Anda dapat menggunakan apa pun yang mengimplementasikan SortedMap, tetapi kecuali untuk kasus yang jarang terjadi, ini TreeMapsama dengan menggunakan Mapimplementasi yang biasanya berarti HashMap.

Untuk kasus di mana kunci Anda adalah tipe kompleks yang tidak mengimplementasikan Sebanding atau Anda tidak ingin menggunakan tatanan alami itu TreeMapdan TreeSetmemiliki konstruktor tambahan yang memungkinkan Anda memasukkan dalam 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());

Ingat ketika menggunakan a TreeMapatau TreeSetitu akan memiliki karakteristik kinerja yang berbeda dari HashMapatau HashSet. Secara kasar operasi yang menemukan atau menyisipkan elemen akan beralih dari O (1) ke O (Log (N)) .

Dalam a HashMap, pindah dari 1000 item ke 10.000 tidak benar-benar mempengaruhi waktu Anda untuk mencari elemen, tetapi untuk TreeMapwaktu pencarian akan menjadi sekitar 3 kali lebih lambat (dengan asumsi Log 2 ). Pindah dari 1000 menjadi 100.000 akan menjadi sekitar 6 kali lebih lambat untuk setiap pencarian elemen.

Jherico
sumber
Saya mencoba menggunakan Treemap dan mengurutkan kunci String berdasarkan panjangnya. Saya menemukan saya mendapatkan hasil pengambilan yang tidak konsisten. Tampaknya karena TreeMap menganggap hasil compareTo dari 0 sebagai "sama dengan"? Tidak yakin bagaimana menggunakannya dalam kasus ini.
Marc
1
bandingkanTo () hasil 0 adalah 'sama dengan'. Jika Anda menulis komparator yang mengurutkan berdasarkan panjang string, maka Anda harus mengembalikan nilai positif atau negatif berdasarkan string mana yang lebih panjang, dan hanya mengembalikan 0 jika kedua string memiliki panjang yang sama. jika a dan b adalah string, Anda bisa melakukan ini seperti `return a.length () - b.length () '(atau membalikkan nilai jika Anda ingin mereka diurutkan ke arah lain).
Jherico
Halo teman-teman, jika dia ingin Map untuk dipesan dengan kunci, yang di sini 1,2,3,4, apa urutan penyisipan .... mengapa kita tidak menggunakan LinkedHashSet? Kami hanya memasukkan pertanyaan satu per satu, dan itu dipesan berdasarkan urutan penyisipan. Bisakah beberapa membantu saya dengan ini?
Karoly
@Karoly LinkedHashSet akan berfungsi untuk mengambil elemen dalam urutan yang Anda masukkan. Yang diinginkan OP adalah mengambil elemen-elemen dalam beberapa urutan sortir yang telah ditentukan, terlepas dari urutan penyisipan.
David Berry
@ cricket_007 kode ini menunjukkan secara spesifik cara beralih di seluruh tombol mereka untuk peta yang belum diurutkan.
Jherico
137

Mengasumsikan TreeMap tidak baik untuk Anda (dan dengan asumsi Anda tidak dapat menggunakan obat generik):

List sortedKeys=new ArrayList(yourMap.keySet());
Collections.sort(sortedKeys);
// Do what you need with sortedKeys.
TrayMan
sumber
3
Terima kasih! Saya perlu melakukan sesuatu seperti ini karena kunci saya adalah tipe yang kompleks.
Ross Hambrick
3
Ini hanya akan mengurutkan daftar kunci, tetapi tidak akan mengurutkan peta itu sendiri berdasarkan kunci. Saya juga mencari cara mengurutkan peta berdasarkan tombol dan dapat menemukan cara. Saya harus mencoba dengan TreeMap kurasa :)
Crenguta S
55

Menggunakan TreeMapAnda dapat mengurutkan peta.

Map<String, String> map = new HashMap<>();        
Map<String, String> treeMap = new TreeMap<>(map);
for (String str : treeMap.keySet()) {
    System.out.println(str);
}
Manoj Singh
sumber
1
Peta <String, List <String>> treeMap = new TreeMap <String, List <String>> (printHashMap); untuk (String str: treeMap.keySet ()) {System.out.println (str + "" + treeMap.get (str)); }
vikramvi
37

Gunakan TreeMap !

AgileJon
sumber
31
+1 - Tidak cukup gesit untuk mengalahkan Jherico, Jon, tetapi masih cukup bagus. 8)
duffymo
Saya tidak tahu Java :-( Ini bekerja 100%. Jauh lebih sederhana daripada solusi mengerikan yang saya buat
peterchaula
36

Jika Anda sudah memiliki peta dan ingin mengurutkannya pada tombol, cukup gunakan:

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

Contoh kerja lengkap:

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
MD
sumber
36

Cukup gunakan TreeMap

new TreeMap<String, String>(unsortMap);

Ketahuilah bahwa TreeMap disortir berdasarkan urutan alami 'kuncinya'

Aliti
sumber
19

Asalkan Anda tidak dapat menggunakan TreeMap, di Java 8 kami dapat menggunakan metode toMap ()Collectors yang mengambil parameter berikut:

  • keymapper : fungsi pemetaan untuk menghasilkan kunci
  • valuemapper : fungsi pemetaan untuk menghasilkan nilai
  • mergeFunction : fungsi menggabungkan, digunakan untuk menyelesaikan tabrakan antara nilai yang terkait dengan kunci yang sama
  • mapSupplier : fungsi yang mengembalikan Peta baru yang kosong ke mana hasilnya akan dimasukkan.

Contoh 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));

Kita dapat memodifikasi contoh untuk menggunakan komparator khusus dan mengurutkan berdasarkan kunci sebagai:

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));
akhil_mittal
sumber
hanya bekerja di Android dengan Api 24 dan lebih tinggi.
Tina
10

Menggunakan 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));
Taras Melnyk
sumber
5

Kode ini dapat mengurutkan peta nilai kunci di kedua pesanan yaitu naik dan turun.

<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;
}

Sebagai contoh:

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

Di Jawa 8

Untuk mengurutkan Map<K, V>berdasarkan kunci, masukkan kunci ke List<K>:

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

Untuk mengurutkan Map<K, V>berdasarkan kunci, masukkan entri ke List<Map.Entry<K, V>>:

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

Last but not least: untuk mengurutkan string dengan cara yang peka terhadap lokal - gunakan kelas Collator (pembanding):

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());
Oleksandr Pyrohov
sumber
1
List<String> list = new ArrayList<String>();
Map<String, String> map = new HashMap<String, String>();
for (String str : map.keySet()) {
 list.add(str);
}
Collections.sort(list);
for (String str : list) {
 System.out.println(str);
}
Manoj Singh
sumber
1

Di Java 8 Anda juga dapat menggunakan .stream (). Diurutkan ():

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

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

Kita juga bisa mengurutkan kunci dengan menggunakan metode 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);
}
Manoj Singh
sumber
Ini mengurutkan berdasarkan nilai dan bukan kunci.
raaj
0

Kalau-kalau Anda tidak ingin menggunakan 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;
}

Juga, dalam kasus Anda ingin menyortir peta Anda atas dasar valuesperubahan hanya Map.Entry::getKeyuntukMap.Entry::getValue

Ankit Sharma
sumber
Ini muncul di log ulasan saya. Seseorang mencoba memperbaiki beberapa kesalahan dengan nama variabel (tetapi gagal). Jadi, saya memperbaikinya dengan benar, namun, jawaban ini salah secara mendasar. Urutan di mana Anda menambahkan nilai ke HashMap tidak relevan. Peta tidak memiliki urutan. stackoverflow.com/questions/10710193/…
aepryus