我想用Java 8的流和LAMBDAS将对象列表翻译成一个映射。
这就是我在Java 7和下面写的方法。
1 2 3 4 5 6 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和番石榴来完成这件事,但我想知道如何在没有番石榴的情况下做到这一点。
番石榴:
1 2 3 4 5 6 7 8 9
| 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();
}
});
} |
和番石榴与爪哇8 lambdas。
1 2 3
| private Map <String, Choice > nameMap (List <Choice > choices ) {
return Maps. uniqueIndex(choices, Choice::getName );
} |
- 您可以看到我的答案,如何使用泛型和控制反转:stackoverflow.com/a/5133442/2590960
基于Collectors文档,它简单如下:
1 2 3
| Map <String, Choice > result =
choices. stream(). collect(Collectors. toMap(Choice::getName,
Function. identity())); |
- 另一方面,即使在Java 8之后,JDK仍然不能在简短的竞争中竞争。番石榴的替代品看起来可读性很强:Maps.uniqueIndex(choices, Choice::getName)。
- @ BogdanCalmac,在Java 8中编写这样的EDCOX1×1方法本身是非常微不足道的。
- 从JOOL库中使用(静态导入)EDOCX1 2(我将推荐给任何使用Java 8的人),也可以用EDCOX1×3来改进简洁性。
- 使用function.identity有什么好处吗?我的意思是,它比
- @我不知道有什么好处,我自己也用了it -> it。这里使用Function.identity(),主要是因为它在参考文献中使用,这是我写作时所知道的关于lambda的全部内容。
- @扎普,哦,事实上,这背后是有原因的——stackoverflow.com/questions/28032827/&hellip;
- 你可以看到我的答案。如何使用泛型和控制反转将列表转换为映射:stackoverflow.com/a/5133442/2590960
- 如果您需要考虑复制密钥,请通过@ulises检查答案。需要使用map>而不是map
- 热访问,例如选择::GetOtherObject::Gename?拜托
如果您的密钥不能保证对列表中的所有元素都是唯一的,则应将其转换为Map>,而不是Map。
1 2
| Map <String, List <Choice >> result =
choices. stream(). collect(Collectors. groupingBy(Choice::getName )); |
- 这实际上为您提供了map>,它处理非唯一键的可能性,但不是op请求的。在guava中,如果这是您想要的,那么multimaps.index(choices,choice::getname)可能是更好的选择。
- 或者更确切地说,使用guava的multimap在相同键映射到多个值的情况下非常方便。在Guava中,有各种实用方法可以使用这些数据结构,而不是创建map>
- @RichardNichols为什么Guava Multimaps方法是更好的选择?这可能会带来不便,因为它不返回Map对象。
使用getname()作为键,选择本身作为映射的值:
1 2
| Map <String, Choice > result =
choices. stream(). collect(Collectors. toMap(Choice::getName, c -> c )); |
- 请写一些描述以便用户理解。
- 太糟糕了,这里没有更多的细节,因为我最喜欢这个答案。
- Collectors.toMap(Choice::getName,c->c)(短2个字符)
- 等于choices.stream().collect(Collectors.toMap(choice -> choice.getName(),choice -> choice));键的第一个函数,值的第二个函数
- 我知道看到和理解c -> c是多么容易,但是Function.identity()携带更多的语义信息。我通常使用静态导入,这样我就可以使用identity()。
- 阅读此处@handd stackoverflow.com/a/28041480/3488928
这是另外一个,以防您不想使用Collectors.tomap()。
1 2 3 4
| Map <String, Choice > result =
choices. stream(). collect(HashMap <String, Choice >::new,
(m, c ) -> m. put(c. getName(), c ),
(m, u ) -> {}); |
- 您在上面的示例中所展示的,哪个比Collectors.toMap()或我们自己的hashmap更好?
- 这个示例提供了一个如何在地图中放置其他内容的示例。我想要一个不是由方法调用提供的值。谢谢!
- 第三个参数函数不正确。在这里,您应该提供一些函数来合并两个哈希映射,比如hashmap::putall。
列出的大多数答案,如果列表中有重复项,则会错过一个案例。在这种情况下,答案将抛出IllegalStateException。请参阅以下代码以处理列表重复项:
1 2 3 4 5
| public Map <String, Choice > convertListToMap (List <Choice > choices ) {
return choices. stream()
. collect(Collectors. toMap(Choice::getName, choice -> choice,
(oldValue, newValue ) -> newValue ));
} |
One more option in simple way
1 2
| Map <String,Choice > map = new HashMap <>();
choices. forEach(e ->map. put(e. getName(),e )); |
- 使用这个或Java 7类型没有任何差别。
- 我发现这比其他机制更容易阅读和理解发生了什么。
- 这样用Java 8流来询问。
例如,如果要将对象字段转换为映射:
实例对象:
1 2 3 4 5 6 7 8 9 10 11
| class Item {
private String code ;
private String name ;
public Item (String code, String name ) {
this. code = code ;
this. name = name ;
}
//getters and setters
} |
操作将列表转换为映射:
1 2 3 4 5 6
| 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(公开我是一个贡献者)对所有JDK集合类型(包括list和map)都有扩展。
1 2
| ListX <Choices > choices ;
Map <String, Choice > map = choices. toMap(c -> c. getName(),c ->c ); |
我试着这样做,发现使用上面的答案,当使用Functions.identity()作为地图的键时,由于输入问题,使用本地方法(如this::localMethodName)实际工作时出现问题。
在这种情况下,Functions.identity()实际上对类型做了一些事情,因此该方法只能通过返回Object并接受Object的参数来工作。
为了解决这个问题,我放弃了Functions.identity(),转而使用s->s。
因此,在我的例子中,我的代码列出了一个目录中的所有目录,对于每个目录,使用目录的名称作为映射的键,然后使用目录名称调用一个方法并返回一组项,如下所示:
1 2 3
| Map <String, Collection <ItemType >> items = Arrays. stream(itemFilesDir. listFiles(File::isDirectory ))
. map(File::getName )
. collect(Collectors. toMap(s ->s, this::retrieveBrandItems )); |
可以使用intstream创建索引流,然后将其转换为映射:
1 2 3 4
| Map <Integer,Item > map =
IntStream. range(0,items. size())
. boxed()
. collect(Collectors. toMap (i -> i, i -> items. get(i ))); |
- 这不是一个好的选项,因为您对每个元素都执行get()调用,因此增加了操作的复杂性(如果项是哈希映射,则为o(n*k))。
- 不是得到了一个哈希图吗?
- @ IvovanderFeeken代码段中的get(i)位于列表中,而不是映射中。
- @我在说尼古拉斯的话。如果项是哈希图而不是列表,我看不到n*k的复杂性。
我用这个语法
1 2
| Map <Integer, List <Choice >> choiceMap =
choices. stream(). collect(Collectors. groupingBy(choice -> choice. getName())); |
- groupingBy创建Map>,而不是Map。
- 乌利西斯的回答。和,String getName();(非整数)
我将编写如何使用泛型和控制反转将列表转换为映射。只是通用方法!
也许我们有整数列表或者对象列表。所以问题是:地图的关键应该是什么?
创建接口
1 2 3
| public interface KeyFinder<K, E> {
K getKey(E e);
} |
现在使用控制反转:
1 2 3
| 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对象,这个类将选择映射的键
1 2 3 4 5 6
| public class BookKeyFinder implements KeyFinder <Long, Book > {
@Override
public Long getKey (Book e ) {
return e. getPrice()
}
} |
1 2
| Map <String, Set <String >> collect = Arrays. asList(Locale. getAvailableLocales()). stream(). collect(Collectors
. toMap(l -> l. getDisplayCountry(), l -> Collections. singleton(l. getDisplayLanguage()))); |
可以使用流来执行此操作。为了省去明确使用EDCOX1(0)的可能,可以静态地导入EDCOX1 OR 11(如有效Java推荐的第三版)。
1 2 3 4 5
| 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的解决方案
1
| StreamEx. of(choices ). toMap(Choice::getName, c -> c ); |
1
| Map <String,Choice > map =list. stream(). collect(Collectors. toMap(Choice::getName, s ->s )); |
甚至为我服务,
1 2
| Map <String,Choice > map = list1. stream(). collect(()-> new HashMap <String,Choice >(),
(r,s ) -> r. put(s. getString(),s ), (r,s ) -> r. putAll(s )); |
这可以通过两种方式实现。让人成为我们将用来演示的课堂。
1 2 3 4 5 6 7 8 9
| public class Person {
private String name ;
private int age ;
public String getAge () {
return age ;
}
} |
让人成为要转换为地图的人的列表
1.使用简单的foreach和列表中的lambda表达式
1 2
| Map <Integer,List <Person >> mapPersons = new HashMap <>();
persons. forEach(p ->mapPersons. put(p. getAge(),p )); |
2.在给定列表上定义的流上使用收集器。
1 2
| Map <Integer,List <Person >> mapPersons =
persons. stream(). collect(Collectors. groupingBy(Person ::getAge )); |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| 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 ));
} |
1 2 3 4 5 6 7 8
| 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 ); |
双重密钥AA12=asdfasdf,7=eedddad,4=cccc,3=bbb,2=aa_