![](/img/trans.png)
[英]Convert Map<String,List<Person>> to Map<String,List<Employee>>, using Java 8 streams. I did this but how do this without for loop
[英]How do I convert a List<Employee> to Map<Employee, List<String>> using java8?
我有一份员工名单。
我已经覆盖了 Employee 类的 equals 和 hashcode。 我想将员工列表转换为以员工对象为键并以唯一车号列表为值的映射。
PS:列表中也可能有重复的键。 因此,我应该合并列表中存在的汽车编号的值并放入地图中。
请在下面找到我尝试使用迭代的代码。 我想知道如何使用 java 8 来做到这一点。
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public class TestMap {
public static void main(String[] args) {
Map<Employee, List<String>> map = new LinkedHashMap<>();
Employee e1 = new Employee("A", new ArrayList(Arrays.asList("car1", "car2", "car3")));
Employee e2 = new Employee("B", new ArrayList(Arrays.asList("car111", "car222", "car333")));
Employee e3 = new Employee("C", new ArrayList(Arrays.asList("car1111", "car2222", "car3333")));
Employee e4 = new Employee("A", new ArrayList(Arrays.asList("car2", "car3", "car4")));
List<Employee> employeeList = new ArrayList<>();
employeeList.add(e1);
employeeList.add(e2);
employeeList.add(e3);
employeeList.add(e4);
for (Employee employee : employeeList) {
if(map.containsKey(employee)) {
List<String> temp = map.get(employee);
temp.addAll(employee.getCars());
temp = temp.stream().distinct().collect(Collectors.toList());
map.put(employee, temp);
}
else {
List<String> values = new ArrayList<>();
values.addAll(employee.getCars().stream().distinct().collect(Collectors.toList()));
map.put(employee, values);
}
}
System.out.println("map::: "+ map);
}
}
class Employee {
private List<String> cars;
public Employee(String empName, List<String> cars) {
this.empName = empName;
this.cars = cars;
}
public List<String> getCars() {
return cars;
}
public void setCars(List<String> cars) {
this.cars = cars;
}
private String empName;
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((empName == null) ? 0 : empName.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Employee other = (Employee) obj;
if (empName == null) {
if (other.empName != null)
return false;
} else if (!empName.equals(other.empName))
return false;
return true;
}
public String getEmpName() {
return empName;
}
public void setEmpName(String empName) {
this.empName = empName;
}
}
我喜欢获取一段命令式代码并将其转换为函数式......仍然Java流会产生如下丑陋的代码......
Employee e1 = new Employee("A", Arrays.asList("car1", "car2", "car3"));
Employee e2 = new Employee("B", Arrays.asList("car111", "car222", "car333"));
Employee e3 = new Employee("C", Arrays.asList("car1111", "car2222", "car3333"));
Employee e4 = new Employee("A", Arrays.asList("car2", "car3", "car4"));
List<Employee> myList = Arrays.asList(e1, e2, e3, e4);
BinaryOperator<Employee> accumulator = (x, y) -> {
List<String> cars = Stream.concat(x.getCars().stream(), y.getCars().stream()).distinct()
.collect(Collectors.toList());
x.setCars(cars);
return x;
};
Map<Employee, List<String>> collect =
myList
.stream()
.collect(Collectors.groupingBy(x -> x))
.entrySet()
.stream()
.collect(
Collectors.toMap(
e -> e.getKey(),
e -> e.getValue()
.stream()
.reduce(accumulator)
.map(Employee::getCars)
.get())
);
System.out.println(collect);
它将打印:
{Employee [empName=A]=[car1, car2, car3, car4], Employee [empName=B]=[car111, car222, car333], Employee [empName=C]=[car1111, car2222, car3333]}
我不会这样做,太丑了,太做作......
特别是如果你将它与像 Scala 这样的原生函数式语言进行比较......
val emps: List[Employee] = List(
Employee("A", List("car1", "car2", "car3")),
Employee("B", List("car111", "car222", "car333")),
Employee("C", List("car1111", "car2222", "car3333")),
Employee("A", List("car2", "car3", "car4")))
val x = emps.groupBy(_.name)
.map{case (k,cs) => (k,cs.flatMap(_.cars).distinct) }
println(x)
}
case class Employee(name: String, cars: List[String])
// Map(A -> List(car1, car2, car3, car2, car3, car4), C -> List(car1111, car2222, car3333), B -> List(car111, car222, car333))
在 java 中,我会考虑使用vavr这样做,这将导致以下代码:
io.vavr.collection.List<Employee> emps = io.vavr.collection.List.of(
new Employee("A", Arrays.asList("car1", "car2", "car3")),
new Employee("B", Arrays.asList("car111", "car222", "car333")),
new Employee("C", Arrays.asList("car1111", "car2222", "car3333")),
new Employee("A",Arrays.asList("car2","car3","car4")));
io.vavr.collection.Map<String, io.vavr.collection.List<String>>
mapValues = emps.groupBy(emp->emp.getEmpName())
.mapValues( v ->v.flatMap(Employee::getCars).distinct());
System.out.println(mapValues);
在 Vavr 代码和 scala 中,我使用 Employee 名称而不是对象作为键,因为它看起来很合适,无法选择一个员工实例而不是另一个,所以我使用了键。
可以简单地通过使用Set
而不是List
来解决:
Map<Employee, Set<String>> collect = employeeList.stream()
.collect(Collectors.groupingBy(Function.identity(),
Collectors.flatMapping(employee -> employee.getCars().stream(), Collectors.toSet())));
输出:
{Employee{name='A'}=[car2, car3, car1, car4], Employee{name='B'}=[car333, car222, car111], Employee{name='C'}=[car1111, car2222, car3333]}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.