Javaでキーによってマップ値をソートする方法は?


362

キーと値の両方の文字列を持つマップがあります。

データは次のようなものです:

「question1」、「1」、
「question9」、「1」、
「question2」、「4」、
「question5」、「2」

キーに基づいてマップを並べ替えたいのですが。それで、結局、私はquestion1, question2, question3....などを持ちます。


最終的に、私はこのマップから2つの文字列を取得しようとしています。

  • 最初の文字列:質問(順序1 ..10)
  • 2番目の文字列:回答(質問と同じ順序)

現在、私は以下を持っています:

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

これにより、質問が文字列で表示されますが、順序が正しくありません。

回答:


613

簡潔な答え

を使用しTreeMapます。これがまさにそのためです。

このマップが渡され、タイプを判別できない場合は、以下を実行できます。

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

これにより、キーの自然な順序でマップ全体が繰り返されます。


より長い答え

技術的には、を実装するものなら何でも使用できますSortedMapが、まれにこれがに相当する場合を除きTreeMapMap実装を使用すると通常と同じになりHashMapます。

あなたのキーがComparableを実装していないか、そして自然な順序を使用したくない複雑なタイプです例の場合TreeMapTreeSetあなたが渡すことができ、追加のコンストラクタを持っています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());

使用する際に覚えているTreeMapTreeSet、それはよりも異なるパフォーマンス特性がありますことHashMapかをHashSet。要素を検索または挿入する大まかに言うと、操作はO(1)からO(Log(N))になります。

HashMap、1000アイテムから10,000アイテムに移動しても、要素を検索する時間には実際には影響しませんがTreeMap、検索時間は約3倍遅くなります(Log 2を想定)。1000から100,000に移動すると、すべての要素の検索で約6倍遅くなります。


ツリーマップを使用して、文字列キーを長さに基づいてソートしようとしています。検索結果に一貫性がない。どうやらTreeMapは、compareToの結果が0であると「等しい」と見なしているからでしょうか。この場合の使い方がわからない。
Marc

1
compareTo()の結果が0の場合、「等しい」です。文字列の長さで並べ替えるコンパレータを作成する場合、どちらの文字列が長いかに基づいて正または負の値を返す必要があり、両方の文字列が同じ長さの場合にのみ0を返します。aとbが文字列の場合、 `return a.length()-b.length() 'のようにこれを行うことができます(または、他の方向に並べ替えたい場合は値を逆にします)。
Jherico 2013

こんにちはみんな、彼/彼女がキーで順序付けられるマップにここに行くなら、ここでは1,2,3,4です、挿入順序とは何ですか... LinkedHashSetを使用しないのはなぜですか?質問をひとつずつ並べていくだけで、挿入順に並べられます。これを手伝ってくれる人はいますか?
Karoly、2015年

@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
ありがとう!私のキーは複雑なタイプだったので、私はこのようなことをする必要がありました。
ロスハンブリック、2011

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


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

を使用できない場合TreeMapJava 8では、次のパラメーターを使用するtoMap()メソッドを使用できCollectorsます。

  • keymapper:キーを生成するためのマッピング関数
  • valuemapper:値を生成するためのマッピング関数
  • mergeFunction:同じキーに関連付けられた値間の衝突を解決するために使用されるマージ関数
  • mapSupplier:結果が挿入される新しい空のMapを返す関数。

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

Api 24以降を搭載したAndroidでのみ機能します。
ティナ

10

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

このコードは、Key-Valueマップを昇順と降順の両方の順序でソートできます。

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

最後に重要なことですが、ロケールに依存する方法で文字列をソートするには、Collat​​or(コンパレータ)クラスを使用します。

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では、.stream()。sorted()も使用できます。

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 2013

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.