Java 8のストリームとラムダを使ってオブジェクトのリストをMapに変換したい。
これは私がJava 7以下でそれを書く方法です。
private Map<String, Choice> nameMap(List<Choice> choices) {
final Map<String, Choice> hashMap = new HashMap<>();
for (final Choice choice : choices) {
hashMap.put(choice.getName(), choice);
}
return hashMap;
}
これはJava 8とGuavaを使って簡単に実現できますが、Guavaを使わずにこれを行う方法を知りたいです。
グアバ語で:
private Map<String, Choice> nameMap(List<Choice> choices) {
return Maps.uniqueIndex(choices, new Function<Choice, String>() {
@Override
public String apply(final Choice input) {
return input.getName();
}
});
}
そしてJava 8のラムダを持つGuava。
private Map<String, Choice> nameMap(List<Choice> choices) {
return Maps.uniqueIndex(choices, Choice::getName);
}
Map<String, Choice> result =
choices.stream().collect(Collectors.toMap(Choice::getName,
Function.identity()));
あなたのキーが _ではなく_ リスト内のすべての要素に対して一意であることが保証されている場合は、Map<String, List<Choice>>
ではなくMap<String, Choice>
に変換してください
Map<String, List<Choice>> result =
choices.stream().collect(Collectors.groupingBy(Choice::getName));
GetName()をキーとして使用し、それ自体をマップの値として選択します。
Map<String, Choice> result =
choices.stream().collect(Collectors.toMap(Choice::getName, c -> c));
Collectors.toMap()を使用したくない場合のためのもう1つのものです。
Map<String, Choice> result =
choices.stream().collect(HashMap<String, Choice>::new,
(m, c) -> m.put(c.getName(), c),
(m, u) -> {});
リストアップされた答えのほとんどは、 リストが重複した項目を持っているケースを見逃しています 。その場合、答えはIllegalStateException
をスローします。リストの重複を処理するには、以下のコード を参照してください
public Map<String, Choice> convertListToMap(List<Choice> choices) {
return choices.stream()
.collect(Collectors.toMap(Choice::getName, choice -> choice,
(oldValue, newValue) -> newValue));
}
簡単な方法でもう1つのオプション
Map<String,Choice> map = new HashMap<>();
choices.forEach(e->map.put(e.getName(),e));
たとえば、オブジェクトフィールドをマップに変換する場合は、次のようにします。
オブジェクトの例:
class Item{
private String code;
private String name;
public Item(String code, String name) {
this.code = code;
this.name = name;
}
//getters and setters
}
そして操作はリストをマップに変換する:
List<Item> list = new ArrayList<>();
list.add(new Item("code1", "name1"));
list.add(new Item("code2", "name2"));
Map<String,String> map = list.stream()
.collect(Collectors.toMap(Item::getCode, Item::getName));
サードパーティのライブラリを使用しても構わない場合は、AOLの cyclops-react lib(私が寄稿者であることを開示)に、 List を含むすべての JDK Collection _型の拡張機能があります。 _と Map 。
ListX<Choices> choices;
Map<String, Choice> map = choices.toMap(c-> c.getName(),c->c);
私はこれをやろうとしていました、そして、MapへのキーのためにFunctions.identity()
を使うとき、上の答えを使うとき、私はタイプ問題のため実際にうまくいくthis::localMethodName
のようなローカルメソッドを使うことに関する問題がありました。
この場合、Functions.identity()
は実際には型付けに対して何かをするので、メソッドはObject
を返してObject
のパラメータを受け入れることによってのみ機能します。
これを解決するために、私はFunctions.identity()
を捨てて代わりにs->s
を使うことにしました。
つまり、私の場合は、ディレクトリ内のすべてのディレクトリを一覧表示し、それぞれのディレクトリの名前をマップのキーとして使用し、そのディレクトリ名を使用してメソッドを呼び出して項目のコレクションを返すというコードです。
Map<String, Collection<ItemType>> items = Arrays.stream(itemFilesDir.listFiles(File::isDirectory))
.map(File::getName)
.collect(Collectors.toMap(s->s, this::retrieveBrandItems));
IntStreamを使ってインデックスのストリームを作成し、それをMapに変換することができます。
Map<Integer,Item> map =
IntStream.range(0,items.size())
.boxed()
.collect(Collectors.toMap (i -> i, i -> items.get(i)));
generics および 制御の反転 を使用して、リストをマップに変換する方法を書きます。ただ 普遍的な方法!
たぶん - 整数のリスト または オブジェクトのリスト。 それで、問題は以下です: 地図の鍵は何であるべきですか?
インターフェースを作成する
public interface KeyFinder<K, E> {
K getKey(E e);
}
今コントロールの反転を使用して:
static <K, E> Map<K, E> listToMap(List<E> list, KeyFinder<K, E> Finder) {
return list.stream().collect(Collectors.toMap(e -> Finder.getKey(e) , e -> e));
}
たとえば、bookというオブジェクトがある場合、このクラスは地図のキーを選択するためのものです。
public class BookKeyFinder implements KeyFinder<Long, Book> {
@Override
public Long getKey(Book e) {
return e.getPrice()
}
}
私はこの構文を使います
Map<Integer, List<Choice>> choiceMap =
choices.stream().collect(Collectors.groupingBy(choice -> choice.getName()));
Map<String, Set<String>> collect = Arrays.asList(Locale.getAvailableLocales()).stream().collect(Collectors
.toMap(l -> l.getDisplayCountry(), l -> Collections.singleton(l.getDisplayLanguage())));
これを行うためにストリームを使用することは可能です。 Collectors
を明示的に使用する必要性を排除するために、(Effective Java、第3版で推奨されているように)toMap
を静的にインポートすることが可能です。
import static Java.util.stream.Collectors.toMap;
private static Map<String, Choice> nameMap(List<Choice> choices) {
return choices.stream().collect(toMap(Choice::getName, it -> it));
}
これは StreamEx による解決策です
StreamEx.of(choices).toMap(Choice::getName, c -> c);
これには2つの方法があります。私たちがそれを実証するために使用するクラスに人をしましょう。
public class Person {
private String name;
private int age;
public String getAge() {
return age;
}
}
people をマップに変換する人物のリストとする
リスト上での単純なforeachとラムダ式の使用
Map<Integer,List<Person>> mapPersons = new HashMap<>();
persons.forEach(p->mapPersons.put(p.getAge(),p));
2.指定されたリストに定義されているストリーム上のコレクターを使用する.
Map<Integer,List<Person>> mapPersons =
persons.stream().collect(Collectors.groupingBy(Person::getAge));
List<V> choices; // your list
Map<K,V> result = choices.stream().collect(Collectors.toMap(choice::getKey(),choice));
//assuming class "V" has a method to get the key, this method must handle case of duplicates too and provide a unique key.
String array[] = {"ASDFASDFASDF","AA", "BBB", "CCCC", "DD", "EEDDDAD"};
List<String> list = Arrays.asList(array);
Map<Integer, String> map = list.stream()
.collect(Collectors.toMap(s -> s.length(), s -> s, (x, y) -> {
System.out.println("Dublicate key" + x);
return x;
},()-> new TreeMap<>((s1,s2)->s2.compareTo(s1))));
System.out.println(map);
公開鍵AA {12 = ASDFASDFASDF、7 = EEDDDAD、4 = CCCC、3 = BBB、2 = AA}
Map<String,Choice> map=list.stream().collect(Collectors.toMap(Choice::getName, s->s));
この目的を私にも提供します、
Map<String,Choice> map= list1.stream().collect(()-> new HashMap<String,Choice>(),
(r,s) -> r.put(s.getString(),s),(r,s) -> r.putAll(s));
If every new value for the same key name has to be overidden
then below will be the code :
public Map<String, Choice>
convertListToMap(List<Choice> choices) {
return choices.stream()
.collect(Collectors.toMap(Choice::getName,
Function.identity(),
(oldValue, newValue) -> newValue));
}
If all choices have to be grouped in a list for a name then
below will be the code:
public Map<String, Choice>
convertListToMap(List<Choice> choices) {
return choices.stream().collect(Collectors.groupingBy(Choice::getName));
}