Harita değerleri Java'da tuşa göre nasıl sıralanır?


362

Anahtarlar ve değerler için dizeleri olan bir harita var.

Veriler aşağıdaki gibidir:

"soru1", "1"
"soru9", "1"
"soru2", "4"
"soru5", "2"

Haritayı anahtarlarına göre sıralamak istiyorum. Böylece, sonunda, ben olacak question1, question2, question3.... ve benzeri.


Sonunda, bu haritadan iki dize almaya çalışıyorum.

  • İlk Dize: Sorular (1.10. Sırada)
  • İkinci Dize: Yanıtlar (soru ile aynı sırada)

Şu anda aşağıdakilere sahibim:

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

Bu bana bir dize soruları alır ama onlar sıralı değil.

Yanıtlar:


613

Kısa cevap

A kullanın TreeMap. Bu tam olarak bunun için.

Bu harita size iletildiyse ve türü belirleyemiyorsanız, aşağıdakileri yapabilirsiniz:

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

Bu, harita boyunca anahtarların doğal sırasına göre yinelenir.


Daha uzun cevap

Teknik olarak, uygulayan her şeyi kullanabilirsiniz SortedMap, ancak nadir durumlar dışında bu TreeMap, Maptipik olarak bir uygulamayı kullanmak gibi HashMap.

Anahtarlarınızın Karşılaştırılabilir uygulamayan karmaşık bir tür olduğu veya doğal düzeni kullanmak istemediğiniz durumlarda TreeMapve aşağıdakileri TreeSetyapmanıza izin veren ek kuruculara sahip olduğunuz durumlarda 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());

A kullanırken hatırla TreeMapveya TreeSetbunun farklı performans özelliklerine sahip olacağını HashMapya HashSet. Bir öğeyi bulan veya ekleyen kabaca konuşan işlemler O (1) ' den O (Günlük (N))' e gider .

Bir de HashMap, 10,000 1000 öğelerin hareket gerçekten bir elemanın arama için zaman etkilemez, ancak için TreeMaparama süresi yaklaşık 3 kat daha yavaş (Log varsayarak olacaktır 2 ). 1000'den 100.000'e geçmek her öğe araması için yaklaşık 6 kat daha yavaş olacaktır.


Treemap kullanmaya ve uzunluğa göre dize anahtarları sıralamak çalışıyorum. Tutarsız alım sonuçları aldığımı fark ettim. Görünüşe göre TreeMap bir CompareTo sonucunu "eşittir" olarak değerlendirdiğinden? Bu durumda nasıl kullanılacağından emin değilim.
Marc

1
CompareTo () sonucu 'eşittir'. Dize uzunluğuna göre sıralanan bir karşılaştırıcı yazıyorsanız, hangi dizenin daha uzun olduğuna bağlı olarak pozitif veya negatif bir değer döndürmeniz ve yalnızca her iki dize aynı uzunlukta ise 0 döndürmeniz gerekir. a ve b dizeler ise bunu `` a.length () - b.length () döndürün '' gibi yapabilirsiniz (veya diğer yönde sıralanmasını istiyorsanız değerleri ters çevirin).
Jherico

Merhaba arkadaşlar, haritaya anahtarlarla sipariş verilecekse, burada 1,2,3,4, ekleme sırası nedir .... Neden LinkedHashSet kullanmıyoruz? Sadece soruları birer birer koyuyoruz ve ekleme sırasına göre sıralanıyor. Bazıları bana bu konuda yardımcı olabilir mi?
Karoly

@Karoly LinkedHashSet öğeleri yerleştirdiğiniz sırayla almak için çalışır. OP'nin istediği şey, ekleme sırasına bakılmaksızın, öğeleri önceden belirlenmiş bir sıralama düzeninde almaktır.
David Berry

@ cricket_007 kodu, daha önce sıralanmamış bir harita için anahtarlar arasında nasıl yineleneceğini gösterir.
Jherico

137

TreeMap'in sizin için iyi olmadığını varsayarsak (ve jenerikleri kullanamayacağınızı varsayarsak):

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

3
Teşekkürler! Anahtarlarım karmaşık bir tip olduğu için böyle bir şey yapmam gerekiyordu.
Ross Hambrick

3
Bu sadece anahtar listesini sıralar, ancak haritanın kendisini anahtarlara göre sıralamaz. Ayrıca haritayı anahtarlara göre nasıl sıralayacağımı ve bir yol bulabileceğimi de arıyorum. Sanırım TreeMap ile denemek zorunda kalacağım :)
Crenguta S

55

Haritayı kullanarak TreeMapsıralayabilirsiniz.

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 = new TreeMap eşlemesini <String, List <String>> (printHashMap); for (String str: treeMap.keySet ()) {System.out.println (str + "" + treeMap.get (str)); }
vikramvi

37

Bir TreeMap kullanın !


31
+1 - Jherico, Jon'u yenecek kadar çevik değil, ama yine de oldukça iyi. 8)
duffymo

Java bilmiyorum :-( Bu% 100 çalışıyor. Geldiğim korkunç çözümlerin herhangi birinden çok daha basit
peterchaula

36

Zaten bir haritanız varsa ve bunu tuşlara göre sıralamak istiyorsanız, şunu kullanın:

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

Tam bir çalışma örneği:

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

Sadece TreeMap kullanın

new TreeMap<String, String>(unsortMap);

TreeMap'in 'anahtarlarının' doğal sırasına göre sıralandığını unutmayın


19

Eğer kullanamazsınız Sağlanan TreeMap, içinde Java 8 biz yararlanabilirler tomap () yöntemi Collectorshangi parametrelerin aşağıdaki alır:

  • keymapper : anahtar üretmek için haritalama fonksiyonu
  • valuemapper : değer üretmek için haritalama fonksiyonu
  • mergeFunction : aynı anahtarla ilişkili değerler arasındaki çakışmaları çözmek için kullanılan bir birleştirme işlevi
  • mapSupplier : sonuçların ekleneceği yeni, boş bir Harita döndüren bir işlev.

Java 8 Örneği

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

Özel karşılaştırıcıyı kullanmak ve anahtarlara dayalı olarak sıralamak için örneği değiştirebiliriz:

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

10

Java 8'i kullanma :

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

Bu kod, bir anahtar / değer eşlemesini her iki düzende de artırabilir, yani artan ve azalan.

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

Örnek olarak:

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

5

Java 8'de

A Map<K, V>tuşunu sıralamak için tuşları a List<K>:

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

A Map<K, V>tuşunu sıralamak için girişleri a List<Map.Entry<K, V>>:

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

Son fakat en az değil: dizeleri yerel ayara duyarlı bir şekilde sıralamak için - bir Collator (karşılaştırıcı) sınıfı kullanın:

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

1

Java 8'de .stream (). Sort () öğesini de kullanabilirsiniz:

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

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

0

Anahtarı Arrays.sort yöntemini kullanarak da sıralayabiliriz.

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

Bu, anahtar yerine değere göre sıralamadır.
raaj

0

Sadece kullanmak istemiyorsanız 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;
}

Ayrıca, in-case sen temelinde haritanızı sıralamak istedim valuessadece değişim Map.Entry::getKeyiçinMap.Entry::getValue


Bu inceleme günlüğümde geldi. Birisi değişken isimleriyle bazı hataları düzeltmeye çalıştı (ancak başarısız oldu). Bu yüzden onları doğru bir şekilde düzelttim, ancak bu cevap temelde yanlış. Bir HashMap'e değer ekleme sırası ilgisizdir. Haritaların sırası yok. stackoverflow.com/questions/10710193/…
aepryus
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.