簡體   English   中英

Java 8集合合並列表

[英]Java 8 Collections Merging List

我正在嘗試使用員工姓名合並集合。

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

Employee具有String nameList Address Address是一個String

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對這些數據進行排序的最佳方法。

如果Java 9是一個選項,你可以使用flatMapping

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

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

如果您使用具有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和地址的列表不能更改ListListIterable ,那么你可以使用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 Collections的提交者。

shmosel的答案很好,因為它充分利用了新的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());

創建地圖輸入對象並從中提取數據有點麻煩,但並不可怕。 如果你願意,可以將這里的一些習語提取到實用方法中,使事情變得更清晰。

這是您的問題的可能解決方案 - 如果您想避免重復值,請使用Set; 否則,使用List:

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()));

}

嘗試這個:

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'}]}]

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM