我的列表如下:
List<Address> address;
其中
Address:
city
country
state
我想将其转换为类似
Map <String,String> convertedMap=list.stream().collect
(Collectors.toMap(Address:getCity+Address:getCountry ,Address:getState));
我要在生成的映射中保留所有重复的键和值,如下所示。
(key=City1country1, value= state1) ,(key=City1country1, value=state2),(key=City1country1,value= state1) ;
答案 0 :(得分:1)
如评论中所述,地图不存储重复的键,因此您必须使用Map<String, List<String>>
代替Map<String, String>
。
总而言之,您只需要使用带有Collectors.toMap
参数的mergeFunction
方法即可处理重复的键。每次出现相同的键时都会调用此操作。在这种情况下,我们只需将两个列表合并为一个即可。看看下面的代码(与JDK 11一起编译),我相信它完全可以满足您的需要并打印出预期的结果(当然使用List<String>
)。
import java.util.*;
import java.util.stream.Collectors;
public class ListToMapWithDuplicatedKeysSample {
public static void main(String[] args) {
List<Address> addresses = List.of(
new Address("City1", "country1", "state1"),
new Address("City1", "country1", "state2"),
new Address("City1", "country1", "state1"),
new Address("City3", "country3", "state3")
);
Map<String, List<String>> result = addresses.stream()
.collect(
Collectors.toMap(
address -> address.getCity() + address.getCountry(),
address -> Collections.singletonList(address.getState()),
ListToMapWithDuplicatedKeysSample::mergeEntriesWithDuplicatedKeys
)
);
System.out.println(result);
}
private static List<String> mergeEntriesWithDuplicatedKeys(List<String> existingResults, List<String> newResults) {
List<String> mergedResults = new ArrayList<>();
mergedResults.addAll(existingResults);
mergedResults.addAll(newResults);
return mergedResults;
}
private static class Address {
private final String city;
private final String country;
private final String state;
public Address(String city, String country, String state) {
this.city = city;
this.country = country;
this.state = state;
}
String getState() {
return state;
}
String getCountry() {
return country;
}
String getCity() {
return city;
}
}
}
答案 1 :(得分:1)
这类事情是许多编码挑战的普遍要求,如果有时间限制,这是一种完成所需内容的快速方法,我选择使用集合而不是列表来查找时间为O (1)而不是O(N):
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
class MapExample {
public static void main(String[] args) {
List<String> addressesList = new ArrayList<>();
addressesList.add("Portland USA ME");
addressesList.add("Portland USA OR");
addressesList.add("Boston USA MA");
System.out.println(cityToStatesMap(addressesList));
}
private static Map<String, Set<String>> cityToStatesMap(List<String> addressesList) {
Map<String, Set<String>> result = new HashMap<>();
if (addressesList == null || addressesList.size() == 0) {
return result;
}
for (String address : addressesList) {
String[] addressComponents = address.split(" ");
String city = addressComponents[0];
String country = addressComponents[1];
String state = addressComponents[2];
String key = city + country;
Set<String> states = result.computeIfAbsent(key, k -> new HashSet<>());
states.add(state);
result.put(key, states);
}
return result;
}
}
输出:
{PortlandUSA=[ME, OR], BostonUSA=[MA]}
注意:我认为您应该使用,
之类的符号作为分隔符而不是空格,这样可以更轻松地处理带有多个单词的城市,例如纽约,旧金山等
答案 2 :(得分:1)
您不能使用Collectors.toMap,因为它需要唯一的密钥。相反,您想要的是groupingBy,它返回每个键的收集值:
class Location {
public final String city;
public final String country;
Location(Address address) {
this.city = address.getCity();
this.country = address.getCountry();
}
@Override
public boolean equals(Object obj) {
if (obj instanceof Location) {
Location other = (Location) obj;
return Objects.equals(this.city, other.city) &&
Objects.equals(this.country, other.country);
}
return false;
}
@Override
public int hashCode() {
return Objects.hash(city, country);
}
}
Map<Location, Set<String>> statesByLocation = addresses.stream().collect(
Collectors.groupingBy(Location::new,
Collectors.mapping(Address::getState, Collectors.toSet())));
您可以使用各种技巧来组合城市和国家(例如两个字符串的列表),但是您实际上应该像上面所示那样制作一个密钥类。该代码将更容易使用,特别是如果您(或另一个开发人员)应该有理由在六个月内重新使用它。
关于收集器方法:
Collectors.groupingBy(Location::new
等效于address -> new Location(address)
,并在地图中创建每个键。Collectors.mapping(Address::getState, Collectors.toSet())
意味着对应于特定键的每个Address都将被调用getState(),并且所产生的字符串将被汇总到Set中以形成Map值。我个人认为我会选择简单的for循环而不是难以理解的Stream方法:
Map<Location, Set<String>> statesByLocation = new HashMap<>();
for (Address address : addresses) {
statesByLocation.computeIfAbsent(new Location(address),
k -> new HashSet<String>()).add(address.getState());
}
答案 3 :(得分:0)
使用具有以下方法签名的toMap
toMap(Function k, Function v,BinaryOperator m)
BinaryOperator 会通知JVM如果遇到重复的密钥该怎么办。在您的情况下,如果遇到重复项,则应将它们合并。
因此 s1 +“,” + s2
因此您的解决方案变为
Map<String, String> map = list.stream().
collect(Collectors.toMap((address -> {
String y = address.getCity() + address.getCountry();
return y + s;
}), Address::getState, (s1, s2) -> s1 + "," + s2));
输出
country3City3 state3
country1City1 state1,state2,state1
Process finished with exit code 0