Java Stream:Create New List from 2 Lists Keeping Only Matching Values

Find element matching in 2 lists using java 8 stream

Define yourself a key object that holds and compares the desired properties. In this simple case, you may use a small list whereas each index corresponds to one property. For more complex cases, you may use a Map (using property names as keys) or a dedicated class:

Function<Person,List<Object>> toKey=p -> Arrays.asList(p.getName(), p.getAge());

Having such a mapping function. you may use the simple solution:

list1.stream().map(toKey)
.flatMap(key -> list2.stream().map(toKey).filter(key::equals))
.forEach(key -> System.out.println("{name="+key.get(0)+", age="+key.get(1)+"}"));

which may lead to poor performance when you have rather large lists. When you have large lists (or can’t predict their sizes), you should use an intermediate Set to accelerate the lookup (changing the task’s time complexity from O(n²) to O(n)):

list2.stream().map(toKey)
.filter(list1.stream().map(toKey).collect(Collectors.toSet())::contains)
.forEach(key -> System.out.println("{name="+key.get(0)+", age="+key.get(1)+"}"));

In the examples above, each match gets printed. If you are only interested in whether such a match exists, you may use either:

boolean exists=list1.stream().map(toKey)
.anyMatch(key -> list2.stream().map(toKey).anyMatch(key::equals));

or

boolean exists=list2.stream().map(toKey)
.anyMatch(list1.stream().map(toKey).collect(Collectors.toSet())::contains);

Java - How can I merge 2 lists based on a third?

I think this solution will work - it preserves the order of the lists, and gave the correct answers to all the samples shown above. By keeping the reference list as a hashMap of indexes, it allows to quickly query for any two integers if one can appear before the other by the reference. I added a printout in a main to test.

 public class ListMergeByRef {

public Map<Integer, List<Integer>> refMap = new HashMap<Integer,List<Integer>>();
public ListMergeByRef(List<Integer> reference) {
int elementIndex = 0;
for (Integer element:reference) {
List<Integer> refListPerElement = refMap.get(element);
if (refListPerElement == null) {
refListPerElement = new ArrayList<Integer>();
}
refListPerElement.add(elementIndex);
elementIndex++;
refMap.put(element, refListPerElement);
}
}

public List<Integer> mergeLists (List<Integer> first, List<Integer> second) {
int firstIndex = 0;
int secondIndex = 0;
List<Integer> merged = new ArrayList<Integer>();
while (firstIndex < first.size() || secondIndex < second.size()) {
if (firstIndex == first.size()) {
merged.addAll(second.subList(secondIndex, second.size()));
return merged;
} else if (secondIndex == second.size()) {
merged.addAll(first.subList(firstIndex, first.size()));
return merged;
}

if (first.get(firstIndex).equals(second.get(secondIndex))){
merged.add(first.get(firstIndex));
firstIndex++;
secondIndex++;
}
else if (isElementAllowedBeforeOther(first.get(firstIndex), second.get(secondIndex))) {
merged.add(first.get(firstIndex));
firstIndex++;
} else {
merged.add(second.get(secondIndex));
secondIndex++;
}
}
return merged;
}

public boolean isElementAllowedBeforeOther(Integer firstElement, Integer secondElement) {
List<Integer> firstElementIndexes = refMap.get(firstElement);
List<Integer> secondElementIndexes = refMap.get(secondElement);
if (firstElementIndexes == null || firstElementIndexes.isEmpty()) return false;
if (secondElementIndexes == null || secondElementIndexes.isEmpty()) return true;
if (firstElementIndexes.get(0) < secondElementIndexes.get(secondElementIndexes.size()-1)) return true;
return false;
}

public static void main(String[] args) {
List<Integer> ref = Arrays.asList(new Integer[] {1,2,3,4,5,6,4,7,8});
List<Integer> first = Arrays.asList(new Integer[] {2,3,4,5,7});
List<Integer> second = Arrays.asList(new Integer[] {4,7,8});
ListMergeByRef merger = new ListMergeByRef(ref);
List<Integer> mergedList = merger.mergeLists(first, second);
for (Integer element: mergedList) {
System.out.print(element+" ");
}
System.out.println();
}

Merging objects from two list with unique id using Java 8

Based on your updated question:

List<Human> humans = ... // init 
List<SuperHuman> superHumans = ... // init

Set<Long> superHumanIds = superHumans.stream()
.map(SuperHuman::getHumanId)
.collect(toSet());

humans.stream()
.filter(human -> superHumanIds.contains(human.getHumanId()))
.map(this::convert)
.forEach(superHumans::add);

superHumans.sort(Comparator.comparing(SuperHuman::getAge));

Assuming this class has another method with the following signature:

private Superhuman convert(Human human) {
// mapping logic
}


Related Topics



Leave a reply



Submit