我正在尝试使用流和lambda将多个集合缩减为单个集合。但是我需要指出重复命中的位置。
基本上我有以下情况:
客户(所有人)的集合1
Person 1 (Tom)
Person 2 (Bob)
Person 3 (Joe)
前景集合2
Person 1 (Mike)
Person 2 (Wilbur)
Person 3 (Joe)
员工收集3
Person 1 (Mike)
Person 2 (Tony)
Person 3 (Sue)
Person 4 (Joe)
我想将这个集合转换为包含一个我可以使用Map做的新字段 - 我迷失了它实际上是如何压扁它以便最终结果将是这样的
集合
Person 1 (Tom, "Customer")
Person 2 (Bob, "Customer")
Person 3 (Joe, "Customer, Prospect, Employee")
Person 4 (Mike, "Prospect, Employee")
Person 5 (Wilbur, "Prospect")
Person 6 (Tony, "Employee")
Person 7 (Sue, "Employee")
我只是计划创建一个字符串值来直观地表示它们属于哪个区域。
谢谢!
[编辑]
根据以下建议,我能够以这种方式测试解决方案......
class TestOutFlatMap { public void test(){
Map<String, Collection<Person>> map = new HashMap<>();
Collection<Person> p1 = new ArrayList<>();
p1.add(new Person("Mike"));
p1.add(new Person("Joe"));
p1.add(new Person("Tony"));
Collection<Person> p2 = new ArrayList<>();
p1.add(new Person("Wilbur"));
p1.add(new Person("Joe"));
p1.add(new Person("Molly"));
Collection<Person> p3 = new ArrayList<>();
p1.add(new Person("Wilbur"));
p1.add(new Person("Joe"));
p1.add(new Person("Bubba"));
map.put("Customer", p1);
map.put("Prospect", p2);
map.put("Employee", p3);
Map<Person, String> output = map
.entrySet()
.stream()
.flatMap(t -> t.getValue().stream().map(g -> new Pair<>(t.getKey(), g)))
.collect(Collectors.toMap(t -> t.getValue(), u -> u.getKey(), (x, y) -> x + ", " + y));
output.keySet().stream().forEach(p -> {
System.out.println(p);
System.out.println(output.get(p));
});
}
class Person {
String name;
Person(String name){
this.name = name;
}
public String toString () {return this.name;}
@Override
public int hashCode() {
int hash = 5;
return hash;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final Person other = (Person) obj;
if (!Objects.equals(this.name, other.name)) {
return false;
}
return true;
}
};
}
但是我的结果并不像预期的那样。他们返回如下:
Bubba
Customer
Molly
Customer
Wilbur Customer, Customer
Tony Customer
Joe Customer, Customer, Customer
Mike Customer
我没有看到它在哪里连接不正确。
答案 0 :(得分:1)
由于您有多个不同类型的集合,因此每个集合都应该有一些标识符。因此,最好的方式是将您的输入表示为集合映射,其中映射的键表示集合的类型,例如Customer,Prospect和Employee。
现在,假设您有Map<String, Collection<Person>>,
,则需要按集合的每个元素进行分组,并跟踪关联的密钥。为此,您需要使用flatmap。
以下代码应该有效:
Map<String, Collection<Person>> map = new HashMap<>();
map.put("Customer", ...);
map.put("Prospect", ...;
map.put("Employee", ...;
Map<Person, String> output = map
.entrySet()
.stream()
.flatMap(t -> t.getValue().stream().map(g -> new Pair<>(t.getKey(), g)))
.collect(Collectors.toMap(
t -> t.getValue(), u -> u.getKey(), (x, y) -> x + ", " + y));
请注意,对类使用的是javafx.util.Pair。
答案 1 :(得分:1)
您可以尝试使用下游收集器进行分组,将组转换为字符串,如下所示:
Map<Person, String> result = map
.entrySet()
.stream()
.flatMap(e -> e.getValue().stream().map(v -> new AbstractMap.SimpleEntry<>(v,e.getKey())))
.collect(
Collectors.groupingBy(Map.Entry::getKey, // group Map.Entry by key
Collectors.mapping(Map.Entry::getValue, // for each group, convert Map.Entry into the value
Collectors.joining(",")))); // convert the values into a comma-delimited String
如果在同一类别键下可以找到两次相同的Person
,并且您希望每个Person
都有唯一的类别,那么您可以将每个组收集到{{1要使组元素唯一,然后使用Set
将Set
转换为String
,如下所示:
Collectors.collectingAndThen
通过以下设置,
Map<Person, String> result = map
.entrySet()
.stream()
.flatMap(e -> e.getValue().stream().map(v -> new AbstractMap.SimpleEntry<>(v,e.getKey())))
.collect(Collectors.groupingBy(
Map.Entry::getKey,
Collectors.mapping(Map.Entry::getValue,
Collectors.collectingAndThen(
Collectors.toSet(), x -> String.join(",",x)))));
我得到 Map<String, Collection<Person>> map = new HashMap<>();
Person person1 = new Person("Person1");
Person person2 = new Person("Person2");
map.put("Customer", Arrays.asList(person1, person2));
map.put("Prospect", Arrays.asList(person1));
map.put("Employee", Arrays.asList(person2, person2));