[英]Merging objects from two list with unique id using Java 8
class Human {
Long humanId;
String name;
Long age;
}
class SuperHuman {
Long superHumanId;
Long humanId;
String name;
Long age;
}
我有兩個清單。 人類名單和superHumans名單。 我想從兩個中創建一個單獨的列表,確保如果一個人是超人,它只會在使用java 8的列表中出現一次。有一個巧妙的方法嗎? 更新:這些是不同的類,即不擴展另一個。 我想最終的名單是超人。 如果一個人已經是超人,我們就會忽視那個人類的對象。 如果人類不是超人,我們將人類對象轉換為超人類對象。 理想情況下,我希望按照他們的年齡對它們進行排序,以便獲得按日期降序排序的超人列表。
根據您更新的問題:
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));
假設此類具有另一個具有以下簽名的方法:
private Superhuman convert(Human human) {
// mapping logic
}
關於如何重新考慮代碼以使其更好,您還有其他建議,但是如果您不能這樣做,有一種方法 - 通過自定義Collector
並不復雜。
自定義收集器還為您提供了實際決定要保留哪個條目的優勢 - 已經收集的條目或者遇到訂單獲勝的最新條目。 它需要一些代碼更改 - 但是如果您需要它可以實現。
private static <T> Collector<Human, ?, List<Human>> noDupCollector(List<SuperHuman> superHumans) {
class Acc {
ArrayList<Long> superIds = superHumans.stream()
.map(SuperHuman::getHumanId)
.collect(Collectors.toCollection(ArrayList::new));
ArrayList<Long> seen = new ArrayList<>();
ArrayList<Human> noDup = new ArrayList<>();
void add(Human elem) {
if (superIds.contains(elem.getHumanId())) {
if (!seen.contains(elem.getHumanId())) {
noDup.add(elem);
seen.add(elem.getHumanId());
}
} else {
noDup.add(elem);
}
}
Acc merge(Acc right) {
noDup.addAll(right.noDup);
return this;
}
public List<Human> finisher() {
return noDup;
}
}
return Collector.of(Acc::new, Acc::add, Acc::merge, Acc::finisher);
}
假設您有這些條目:
List<SuperHuman> superHumans = Arrays.asList(
new SuperHuman(1L, 1L, "Superman"));
//
List<Human> humans = Arrays.asList(
new Human(1L, "Bob"),
new Human(1L, "Tylor"),
new Human(2L, "John"));
這樣做:
List<Human> noDup = humans.stream()
.collect(noDupCollector(superHumans));
System.out.println(noDup); // [Bob, Tylor]
嘗試這個。
List<Object> result = Stream.concat(
humans.stream()
.filter(h -> !superHumans.stream()
.anyMatch(s -> h.humanId == s.humanId)),
superHumans.stream())
.collect(Collectors.toList());
假設這兩個類都沒有繼承另一個類。 我可以想象你有兩個清單:
Human alan = new Human(1, "Alan");
Human bertha = new Human(2, "Bertha");
Human carl = new Human(3, "Carl");
Human david = new Human(4, "David");
SuperHuman carlS = new SuperHuman(1, 3, "Carl");
SuperHuman eliseS = new SuperHuman(2, 0, "Elise");
List<Human> humans = new ArrayList<>(Arrays.asList(alan, bertha, carl, david));
List<SuperHuman> superHumans = new ArrayList<>(Arrays.asList(carlS, eliseS));
我們看到卡爾被列為人類,也是超人。 存在兩個相同的卡爾實例。
List<Object> newList = humans.stream()
.filter((Human h) -> {
return !superHumans.stream()
.anyMatch(s -> s.getHumanId() == h.getHumanId());
})
.collect(Collectors.toList());
newList.addAll(superHumans);
此代碼試圖篩選人的名單,但不包括其所有條目humanId
存在於超人的列表。 最后,所有超人都加入了。
這個設計有幾個問題:
humanId
和name
),這也表明這些類是相關的。 假設這些類是相關的,絕對不是沒有根據的。
正如其他評論者建議的那樣,您應該重新設計課程:
class Human {
long id; // The name 'humanId' is redundant, just 'id' is fine
String name;
}
class SuperHuman extends Human {
long superHumanId; // I'm not sure why you want this...
}
Human alan = new Human(1, "Alan");
Human bertha = new Human(2, "Bertha");
Human carl = new SuperHuman(3, "Carl");
Human david = new Human(4, "David");
Human elise = new SuperHuman(5, "Elise");
List<Human> people = Arrays.asList(alan, bertha, carl, david, elise);
然后,每個人都有一個單獨的實例。 你有沒有從列表中獲得所有超人,只需使用:
List<Human> superHumans = people.stream()
.filter((Human t) -> t instanceof SuperHuman)
.collect(Collectors.toList());
superHumans.forEach(System.out::println); // Carl, Elise
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.