交叉两个不同对象类型的集合java 8

Gaz*_*arz 4 java collections lambda java-8 java-stream

我有两个对象列表:

List<SampleClassOne> listOne;
List<SampleClassTwo> listTwo;
Run Code Online (Sandbox Code Playgroud)

SampleClassOne:

public class SampleClassOne{
  private String myFirstProperty;
  //ommiting getters-setters
}
Run Code Online (Sandbox Code Playgroud)

SampleClassTwo:

public class SampleClassTwo{
  private String myOtherProperty;
  //ommiting getters-setters
}
Run Code Online (Sandbox Code Playgroud)

RootSampleClass:

public class RootSampleClass{
  private SampleClassOne classOne;
  private SampleClassTwo classTwo;
  //ommiting getters-setters
}
Run Code Online (Sandbox Code Playgroud)

现在我想根据条件将两个列表合并到RootSampleClass类型的新列表中:

if(classOneObject.getMyFirstProperty().equals(classTwoObject.getMyOtherProperty()){
 //create new RootSampleClass based on classOneObject and classTwoObject and add it to another collection
}
Run Code Online (Sandbox Code Playgroud)

伪代码:

foreach(one: collectionOne){
 foreach(two: collectionTwo){
    if(one.getMyFirstProperty().equals(two.getMyOtherProperty()){
    collectionThree.add(new RootSampleClass(one, two));
    }
 }
}
Run Code Online (Sandbox Code Playgroud)

我对java 8感兴趣.我想在这里有最好的表现,这就是为什么我要求现有的解决方案而不编写自定义foreach.

Hol*_*ger 8

直接等效于嵌套循环

List<RootSampleClass> result = listOne.stream()
    .flatMap(one -> listTwo.stream()
        .filter(two -> one.getMyFirstProperty().equals(two.getMyOtherProperty()))
        .map(two -> new RootSampleClass(one, two)))
    .collect(Collectors.toList());
Run Code Online (Sandbox Code Playgroud)

重点是直接等效,其中包括做n×m操作的不良表现.

更好的解决方案是将其中一个列表转换为支持有效查找的数据结构,例如哈希映射.此考虑因素与您使用的API的问题无关.既然您要求Stream API,您可以这样做:

Map<String,List<SampleClassOne>> tmp=listOne.stream()
    .collect(Collectors.groupingBy(SampleClassOne::getMyFirstProperty));
List<RootSampleClass> result = listTwo.stream()
    .flatMap(two -> tmp.getOrDefault(two.getMyOtherProperty(), Collections.emptyList())
        .stream().map(one -> new RootSampleClass(one, two)))
    .collect(Collectors.toList());
Run Code Online (Sandbox Code Playgroud)

请注意,两种解决方案都会创建所有可能的配对,以便在一个或两个列表中多次出现属性值.如果属性值在每个列表中都是唯一的,例如ID,则可以使用以下解决方案:

Map<String, SampleClassOne> tmp=listOne.stream()
    .collect(Collectors.toMap(SampleClassOne::getMyFirstProperty, Function.identity()));
List<RootSampleClass> result = listTwo.stream()
    .flatMap(two -> Optional.ofNullable(tmp.get(two.getMyOtherProperty()))
            .map(one -> Stream.of(new RootSampleClass(one, two))).orElse(null))
    .collect(Collectors.toList());
Run Code Online (Sandbox Code Playgroud)

如果您不介意可能执行双重查找,则可以使用以下更易读的代码替换最后一个解决方案:

Map<String, SampleClassOne> tmp=listOne.stream()
    .collect(Collectors.toMap(SampleClassOne::getMyFirstProperty, Function.identity()));
List<RootSampleClass> result = listTwo.stream()
    .filter(two -> tmp.containsKey(two.getMyOtherProperty()))
    .map(two -> new RootSampleClass(tmp.get(two.getMyOtherProperty()), two))
    .collect(Collectors.toList());
Run Code Online (Sandbox Code Playgroud)