2016-01-29 90 views
2

我試圖合併使用員工姓名的集合。Java 8集合合併列表

我有一個MainDTO具有List<Employee(name, List<Address(String)>)>

EmployeeString nameList Address AddressString

MainDTO -> List<Employee> empList; 
Employee-> String name, List<String> 

我有輸入數據:

(("emp1",[("KY"),"("NY")]), 
    ("em2",[("KY"),"("NY")]), 
    ("emp1",[("MN"),"("FL")]), 
    ("emp1",[("TN"),"("AZ")]) 
) 

輸出將是:

(("emp1",[("KY"),"("NY"),("MN"),"("FL"),("TN"),"("AZ")]), 
    ("em2",[("KY"),"("NY")]) 
) 

用java 8或Java 7.

回答

0

這此數據進行排序的任何最佳方式一個可能的解決方案 - 如果你想避免重複的值,使用Set;否則,使用列表:

public static void main(String[]args){ 
    final List<Map.Entry<String, List<String>>> inputData = new ArrayList<>(); 
    inputData.add(new AbstractMap.SimpleEntry<String, 
      List<String>>("emp1", Arrays.asList("KY","NY"))); 
    inputData.add(new AbstractMap.SimpleEntry<String, 
      List<String>>("emp2", Arrays.asList("KY","NY"))); 
    inputData.add(new AbstractMap.SimpleEntry<String, 
      List<String>>("emp1", Arrays.asList("MN","FL"))); 
    inputData.add(new AbstractMap.SimpleEntry<String, 
      List<String>>("emp1", Arrays.asList("MN","FL"))); 

    //If you do not care about duplicates - use List 
    final Map<String,List<String>> possibleWithDuplicatesData = 
      inputData.stream() 
      .collect(Collectors.toMap(Map.Entry::getKey, 
        entry -> new ArrayList<String>()));  
    inputData.stream() 
    .filter(entry -> possibleWithDuplicatesData.containsKey(entry.getKey())) 
    .forEach(entry-> 
    possibleWithDuplicatesData.get(entry.getKey()).addAll(entry.getValue())); 

    //If you want to avoid duplicates - use Set 
      final Map<String,Set<String>> noDuplicatesData = 
        inputData.stream() 
        .collect(Collectors.toMap(Map.Entry::getKey, 
          entry -> new HashSet<String>()));  
      inputData.stream() 
      .filter(entry -> noDuplicatesData.containsKey(entry.getKey())) 
      .forEach(entry-> 
      noDuplicatesData.get(entry.getKey()).addAll(entry.getValue())); 

} 
0

試試這個:

private static class Address { 

    private String address; 

    public Address(String address) { 
     this.address = address; 
    } 

    public String getAddress() { 
     return address; 
    } 

    public void setAddress(String address) { 
     this.address = address; 
    } 

    @Override 
    public String toString() { 
     return "Address{" + 
       "address='" + address + '\'' + 
       '}'; 
    } 
} 

private static class Employee { 

    private String name; 
    private List<Address> addresses; 

    public Employee(String name, List<Address> addresses) { 
     this.name = name; 
     this.addresses = addresses; 
    } 

    public String getName() { 
     return name; 
    } 

    public void setName(String name) { 
     this.name = name; 
    } 

    public List<Address> getAddresses() { 
     return addresses; 
    } 

    public void setAddresses(List<Address> addresses) { 
     this.addresses = addresses; 
    } 

    @Override 
    public String toString() { 
     return "Employee{" + 
       "name='" + name + '\'' + 
       ", addresses=" + addresses + 
       '}'; 
    } 
} 

private static class MainDTO { 

    private List<Employee> employees; 

    public MainDTO(List<Employee> employees) { 
     this.employees = employees; 
    } 

    public List<Employee> getEmployees() { 
     return employees; 
    } 

    public void setEmployees(List<Employee> employees) { 
     this.employees = employees; 
    } 

    @Override 
    public String toString() { 
     return "MainDTO{" + 
       "employees=" + employees + 
       '}'; 
    } 
} 

public static void main(String[] args) { 
    List<Employee> employees = new ArrayList<>(); 
    employees.add(new Employee("emp1", Arrays.asList(new Address("KY"), new Address("NY")))); 
    employees.add(new Employee("emp2", Arrays.asList(new Address("KY"), new Address("NY")))); 
    employees.add(new Employee("emp1", Arrays.asList(new Address("MN"), new Address("FL")))); 
    employees.add(new Employee("emp1", Arrays.asList(new Address("TN"), new Address("AZ")))); 
    MainDTO dto = new MainDTO(employees); 

    List<Employee> merged = dto.getEmployees().stream() 
     .collect(Collectors.toMap(Employee::getName, 
            e -> e, 
            (l, r) -> 
             new Employee(l.getName(), 
                 Stream.concat(l.getAddresses().stream(), r.getAddresses().stream()) 
                   .collect(Collectors.toList())), 
            LinkedHashMap::new)) 
     .values() 
     .stream() 
     .collect(Collectors.toList()); 

    System.out.println(merged); 
} 

夫婦筆記:

  • LinkedHashMap的是用來保存列表的原始順序。

  • Stream.concat用於支持Collection.addAll(Collection),因爲它們可以是不可變的。

輸出:

[Employee{name='emp1', addresses=[Address{address='KY'}, Address{address='NY'}, Address{address='MN'}, Address{address='FL'}, Address{address='TN'}, Address{address='AZ'}]}, Employee{name='emp2', addresses=[Address{address='KY'}, Address{address='NY'}]}] 
4

如果你的Java 9是一種選擇,你可以使用flatMapping

Map<String, List<String>> addressesByEmployeeName = empList 
     .stream() 
     .collect(groupingBy(
       Employee::getName, flatMapping(
         e -> e.getAddresses().stream(), 
         toList()))); 

但我有這種奇怪的感覺的Java 9不是一個選項。

+0

不錯的使用新的JDK 9功能! +1。在JDK 8中這可能會更復雜一些;看[我的答案](http://stackoverflow.com/a/35092228/1441122)。 –

1

shmosel's answer不錯,它很好地利用了新的JDK 9 flatMapping收集器。如果JDK 9不是一個選項,那麼可以在JDK 8中做類似的事情,儘管它更復雜一些。它在流內執行平面映射操作,產生一串員工姓名和地址。我將使用AbstractMap.SimpleEntry而不是創建一個特殊的對類。

其基本思想是將員工列表進行流式處理,並將它們平面映射爲一對(名稱,地址)對。完成此操作後,將它們收集到地圖中,按名稱分組,並將地址收集到每個組的列表中。下面的代碼做到這一點:

import static java.util.AbstractMap.SimpleEntry; 
import static java.util.Map.Entry; 
import static java.util.stream.Collectors.*; 

Map<String, List<String>> mergedMap = 
    empList.stream() 
      .flatMap(emp -> emp.getAddresses().stream().map(
         addr -> new SimpleEntry<>(emp.getName(), addr))) 
      .collect(groupingBy(Entry::getKey, mapping(Entry::getValue, toList()))); 

這給出了一個Map結果。如果你想創建這些Employee對象,你可以通過輸入流來創建他們:映射條目對象

List<Employee> mergedEmps = 
    mergedMap.entrySet().stream() 
      .map(entry -> new Employee(entry.getKey(), entry.getValue())) 
      .collect(toList()); 

創作並從中提取數據是有些繁瑣,但並不可怕。如果你願意,這裏的一些成語可以被提取到實用方法中,使事情變得更清潔。

2

如果您使用具有Multimaps的庫(例如Eclipse Collections),這將變得更容易。

ListIterable<Employee> empList = ...; 
MutableSortedSetMultimap<String, String> addressesByEmployeeName = 
    new TreeSortedSetMultimap<>(); 
empList.each(e -> e.getAddresses().each(a -> addressesByEmployeeName.put(e.getName(), a))); 

如果empList和地址的列表不能從List改爲ListIterable,那麼你可以使用ListAdapter得到這個工作。

ListAdapter.adapt(empList).each(
    e -> ListAdapter.adapt(e.getAddresses()).each(
     a -> addressesByEmployeeName.put(e.getName(), a))); 

由於這種模式有點普遍,我們可能會將RichIterable.toMultimap()添加到庫中。那麼這個例子就會歸結爲一行。

MutableListMultimap<String, String> addressesByEmployeeName = 
    empList.toMultimap(Employee::getName, Employee::getAddresses); 

注意:我是Eclipse集合的提交者。