web-dev-qa-db-ja.com

Map <String、String>をMap <Long、String>に変換する方法は? (オプション:グアバを使用)

Map<String, String>Stringキーは「123」などの数値にすぎません。この値はJSFコンポーネントのUIから取得されているため、数値を取得しています。 UIコンポーネントのコントラクトを変更したくない。

次に、Map<Long, String>上記のMapに基づいて、transformクラスにいくつかのMapsメソッドがあることを確認しましたが、すべてがキーではなく変換値に焦点を当てています。

より良い変換方法はありますかMap<String, String>からMap<Long, String>

21
Premraj

Java 8の更新

ストリームを使用してこれを行うことができます:

_Map<Long, String> newMap = oldMap.entrySet().stream()
  .collect(Collectors.toMap(e -> Long.parseLong(e.getKey()), Map.Entry::getValue));
_

これは、すべてのキーがLongsの有効な文字列表現であることを前提としています。また、変換時に衝突が発生する可能性があります。たとえば、_"0"_と_"00"_はどちらも_0L_にマップされます。


私はあなたがマップを反復する必要があると思います:

_Map<Long, String> newMap = new HashMap<Long, String>();
for(Map.Entry<String, String> entry : map.entrySet()) {
   newMap.put(Long.parseLong(entry.getKey()), entry.getValue());
}
_

このコードは、mapのすべての値をサニタイズしたことを前提としています(したがって、無効なlong値はありません)。

より良い解決策があることを願っています。

[〜#〜]編集[〜#〜]

Commons Collection-Utilsの CollectionUtils#transformedCollection(Collection, Transformer) メソッドに出くわしましたが、それはあなたが望むことをするかもしれないようです。 さらに言えば、Collectionを実装するクラスに対してのみ機能します。

20
Vivin Paliath

@Vivinの答えは正しいですが、GuavaにMapのキーを変換できる(またはSetをまったく変換できない)メソッドがない理由を説明すると役立つと思います。

Guavaの変換とフィルタリングのすべてのメソッドは、遅延した結果を生成します...関数/述語は、オブジェクトが使用されるときに必要な場合にのみ適用されます。彼らはコピーを作成しません。そのため、しかし、変換はSetの要件を簡単に破ることができます。

たとえば、「1」と「01」の両方をキーとして含む_Map<String, String>_があるとします。これらは両方とも別個のStringsであるため、Mapは両方をキーとして合法的に含めることができます。ただし、Long.valueOf(String)を使用して変換すると、どちらも値_1_にマッピングされます。それらはもはや別個のキーではありません。マップのコピーを作成してエントリを追加しても、重複したキーはそのキーの以前のエントリを上書きするため、これによって問題が発生することはありません。ただし、遅延変換されたMapには一意のキーを適用する方法がないため、Mapの規約に違反します。

39
ColinD

これで、Java 8ストリーム、マップ、収集を使用して、これをより読みやすくクリーンな方法で実行できます。

Map<String, String> oldMap

Map<Long, String> newMap = oldMap.entrySet().stream()
  .collect(Collectors.toMap(entry -> Long.parseLong(entry.getKey()), Map.Entry::getValue));
24
Vibha Rathi

以下は、結果のマップを変更できないようにするための、以下の回答のいずれかの更新バージョンです(いいえ、Guavaを使用せず、単純にJava 8):

  import static Java.util.stream.Collectors.collectingAndThen;
  import static Java.util.stream.Collectors.toMap;

  ...

  newMap = oldMap.entrySet().stream().collect(collectingAndThen(
              toMap((Map.Entry<String, String> entry) -> transformKey(entry.getKey()),
                    (Map.Entry<String, String> entry) -> transformValue(entry.getValue())),
              Collections::unmodifiableMap)));
3
Evgeny Goldin

短い答えはノーです、グアバは箱から出してこれを提供しません。

簡単な方法は以下のようになります。ただし、注意事項がいくつかあります。

    public static <K, V, L, W> Map<L, W> transformMap(Map<K, V> map, Function<K, L> keyFunction, Function<V, W> valueFunction) {
    Map<L, W> transformedMap = newHashMap();

    for (Entry<K, V> entry : map.entrySet()) {
        transformedMap.put(
                keyFunction.apply(entry.getKey()),
                valueFunction.apply(entry.getValue()));
    }

    return transformedMap;
}

public static <K, V, L> Map<L, V> transformKeys(Map<K, V> map, Function<K, L> keyFunction) {
    return transformMap(map, keyFunction, Functions.<V>identity());
}

Guavaのトランスフォーマーはすべて「遅延」またはビューベースです。マップキートランスフォーマーを実装するには、双方向の関数が必要になると思います。私の理解では、Guavaチームの作業中に、その問題を解決するコンバーターがあるということです。

あなたが遭遇する他の問題は、 " Jimmy-proof "になるために、重複の可能性に対処しなければならないということです。これは、別のグアバの原則です。これを処理する1つの方法は Multimap ;を返すことです。もう1つは、重複が発生したときに例外をスローすることです。私がお勧めしないのは、問題を隠すことです。重複するキーを持つ後続のエントリを無視するか、重複したキーで新しいエントリを上書きします。

2
Ray

Java 8および jOOλ を使用して回答

private static <K1, K2, V> Map<K2, V> mapKeys(Map<K1, V> map, Function<K1, K2> keyMapper) {
    return Seq.seq(map).map(t -> t.map1(keyMapper)).toMap(Tuple2::v1, Tuple2::v2);
}
0
J. Dimeo

これに対する既製の実用的なソリューションを提供する史上最高の投稿は、次の場所にあります。

HashMapの変換Java 8

このサイトには、考えられる3つのケースがすべて示されています。

  1. 地図->地図
  2. 地図->地図
  3. 地図->地図
0
DanDan