使用Java8合并两个具有唯一id的列表中的对象

使用Java8合并两个具有唯一id的列表中的对象,java,java-8,Java,Java 8,我有两张单子。人类名单和超人名单。我想从这两个列表中创建一个列表,确保如果一个人是超人,那么它在使用Java8的列表中只出现一次。有什么好办法吗? 更新:这些是不同的类,即两者都不扩展另一个。我希望最后的名单是超人。如果一个人已经是超人了,我们就忽略了这个人类对象。如果人不是超人,我们就把人的物体变成超人的物体。理想情况下,我希望在最后按他们的年龄对他们进行排序,这样我就可以得到一份按日期降序排列的超人名单。试试这个 class Human { Long humanId; Str

我有两张单子。人类名单和超人名单。我想从这两个列表中创建一个列表,确保如果一个人是超人,那么它在使用Java8的列表中只出现一次。有什么好办法吗? 更新:这些是不同的类,即两者都不扩展另一个。我希望最后的名单是超人。如果一个人已经是超人了,我们就忽略了这个人类对象。如果人不是超人,我们就把人的物体变成超人的物体。理想情况下,我希望在最后按他们的年龄对他们进行排序,这样我就可以得到一份按日期降序排列的超人名单。

试试这个

class Human {
    Long humanId;
    String name;
    Long age;
}


class SuperHuman {
    Long superHumanId;
    Long humanId;
    String name;
    Long age;
}
List result=Stream.concat(
humans.stream()
.filter(h->!superHumans.stream()
.anyMatch(s->h.humanId==s.humanId)),
superHumans.stream())
.collect(Collectors.toList());

根据您更新的问题:

List<Object> result = Stream.concat(
    humans.stream()
        .filter(h -> !superHumans.stream()
            .anyMatch(s -> h.humanId == s.humanId)),
    superHumans.stream())
    .collect(Collectors.toList());

对于如何对代码进行重新分解以使其更好,您还有其他建议,但如果您做不到这一点,有一种方法-通过自定义
收集器
,并不那么复杂

自定义收集器还可以让您实际决定要保留哪个条目—已收集的条目、即将收集的条目或最新的条目获胜。这将需要一些代码更改,但在您可能需要的情况下是可行的

private Superhuman convert(Human human) {
    // mapping logic
}
私有静态收集器noDupCollector(列出超人){
等级Acc{
ArrayList superIds=superHumans.stream()
.map(超人::getHumanId)
.collect(收集器.toCollection(ArrayList::new));
ArrayList seen=新的ArrayList();
ArrayList noDup=新的ArrayList();
无效添加(人类元素){
if(superIds.contains(elem.getHumanId())){
如果(!seen.contains(elem.getHumanId())){
noDup.add(elem);
seen.add(elem.getHumanId());
}
}否则{
noDup.add(elem);
}
}
Acc合并(Acc右){
noDup.addAll(好的,noDup);
归还这个;
}
公共列表完成器(){
返回noDup;
}
}
返回Collector.of(Acc::new、Acc::add、Acc::merge、Acc::finisher);
}
假设您有以下条目:

 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 superHumans=Arrays.asList(
新超人(1L,1L,“超人”);
//
List humans=Arrays.asList(
新人类(1L,“鲍勃”),
新人类(1L,“泰勒”),
新人类(2L,“约翰”);
这样做:

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 noDup=humans.stream()
.收集(noDupCollector(超人));
System.out.println(noDup);//[鲍勃,泰勒]

假设两个类都不继承另一个。我可以想象你有两个清单:

List<Human> noDup = humans.stream()
            .collect(noDupCollector(superHumans));

System.out.println(noDup); // [Bob, Tylor]
人类艾伦=新人类(1,“艾伦”); 人类伯莎=新人类(2,“伯莎”); 人类卡尔=新超人(3,“卡尔”); 人类大卫=新人类(4,“大卫”); 人类elise=新超人(5,“elise”); List people=Arrays.asList(艾伦、伯莎、卡尔、大卫、伊丽莎白); 然后每个人都有一个实例。你能从列表中找到所有的超人吗,只要用这个:

List<Object> newList = humans.stream()
    .filter((Human h) -> {
        return !superHumans.stream()
            .anyMatch(s -> s.getHumanId() == h.getHumanId());
    })
    .collect(Collectors.toList());
newList.addAll(superHumans);
List superHumans=people.stream()
.filter((人类t)->超人的t实例)
.collect(Collectors.toList());
超人.forEach(System.out::println);//卡尔,伊莉丝

超人是否扩展了人类?是的,有一种简洁的方法可以从表面上回答这个问题,但会很笨拙。真正的问题是为什么要这样做?合并相似但重叠类型的数据只会表明设计不好。你可能想让超人成为人类的一个子类,在人类平等的基础上拥有人类的平等,然后将所有东西添加到一个集合中,只在第一个位置创建具有正确类的超人。从你的问题来看,不清楚
人类
超人
之间的关系。您的代码告诉我们一个没有扩展另一个(这有点令人惊讶),但是它们在其他方面是如何关联的?如果一个名叫艾伦的人是一个超人,那么他在这两个列表中到底是如何出现的?你能举一个具体的例子说明结果应该是什么吗?现在有多个答案,结果略有不同,因为你的意图不是100%清楚——这可能会复制人类——OP也不希望that@Eugene在
Human
类中没有
equals()
方法。因此,
结果
无法复制。您是否确实尝试了您的代码?除了包含复制品,它还将丢弃根本不是超人的人类——这是不应该发生的某个地方,这将修复整个代码。。。嗯,差不多了。我认为这个解决方案只有在超人没有
超人ID
,而只有继承的
humanId
的情况下才有效。我的意思是,即使在
Superhuman
classIf
Human
类重写
equals
hashcode
方法中没有重新声明,并且在实现中只考虑
humanId
humanId
的实例及其子类
superhumani
基于
humanId
将是相等的。因此,在场景中只有独一无二的
humanId
',我认为这是基于提供的OP描述的受感染行为。但正如我在问题下方的评论中所述,我们不能确定…@furkan确实,“以正确的方式覆盖”是一个明智的选择。我更新了问题。我应该提供这两个对象没有任何关联的信息。我更新了问题。我应该提供这两个物体没有任何关联的信息。
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);
List<Human> superHumans = people.stream()
    .filter((Human t) -> t instanceof SuperHuman)
    .collect(Collectors.toList());

superHumans.forEach(System.out::println); // Carl, Elise