Java 如何从两个不同对象列表中获取不常见对象

Java 如何从两个不同对象列表中获取不常见对象,java,java-stream,Java,Java Stream,我有两张单子 List<Foo> foolist = getAll(); List<Bar> barList = getAll(); class Foo { String name; String age; .... // more fields } class Bar { String barName; int codeBar; .... // more field } List愚人列表=getAll

我有两张单子

List<Foo> foolist = getAll();
List<Bar> barList = getAll();

class Foo {
    String name;
    String age;
    ....
    // more fields
}

class Bar {
    String barName;
    int codeBar;
    ....
    // more field
}
List愚人列表=getAll();
List barList=getAll();
福班{
字符串名;
弦年龄;
....
//更多领域
}
分类栏{
字符串名称;
内码条;
....
//更多领域
}
我们可以使用agecodeBar和namebarName建立它们之间的关系 我想得到那些不喜欢愚人的东西, 如何使用流来完成

我看到了使用stream().filter(list::contains)的示例,但在本例中它无效

有人能给我指出正确的方向吗

谢谢大家。 我看起来像这样:
barList.stream().filter(b->dublist.stream().anyMatch(f->!b.getBarName().equalsIgnoreCase(f.getName)&&b.getCodeBar()==Integer.valueOf(age)).collector(collector.toList())


我还不知道这是否正确

你可以这样做:

public static void main(String[] args) {
    List<Foo> fooList = asList(new Foo("1", "1"), new Foo("2", "2"), new Foo("3", "3"));
    List<Bar> barList = asList(new Bar("4", 4), new Bar("3", 3), new Bar("5", 5));

    Set<Blah> fooSet = fooList.stream().map(Main::fooToBlah).collect(toCollection(HashSet::new));
    Set<Blah> barSet = barList.stream().map(Main::barToBlah).collect(toCollection(HashSet::new));

    barList.stream()
            .filter(bar -> !fooSet.contains(barToBlah(bar)))
            .forEach(System.out::println);
    fooList.stream()
            .filter(foo -> !barSet.contains(fooToBlah(foo)))
            .forEach(System.out::println);
}

static Blah fooToBlah(Foo foo) {
    return new Blah(foo.name, foo.age);
}

static Blah barToBlah(Bar bar) {
    return new Blah(bar.barName, "" + bar.codeBar);
}

static class Blah {
    String name;
    String age;

    public Blah(String name, String age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public boolean equals(Object o) {
        ...
    }

    @Override
    public int hashCode() {
        ...
    }
}
像这样的事情

barList.stream()
        .filter(bar -> fooList.stream()
                .map(Main::fooToBlah)
                .noneMatch(foo -> foo.equals(barToBlah(bar)))
        )
        .forEach(System.out::println);
甚至可以完全删除
Blah

barList.stream()
        .filter(bar -> fooList.stream().noneMatch(foo -> Objects.equals(foo.name, bar.barName) && Objects.equals(foo.age, "" + bar.codeBar)
        .forEach(System.out::println);

但最终的时间复杂度要差得多,而且还存在可读性问题。

您可以这样做:

public static void main(String[] args) {
    List<Foo> fooList = asList(new Foo("1", "1"), new Foo("2", "2"), new Foo("3", "3"));
    List<Bar> barList = asList(new Bar("4", 4), new Bar("3", 3), new Bar("5", 5));

    Set<Blah> fooSet = fooList.stream().map(Main::fooToBlah).collect(toCollection(HashSet::new));
    Set<Blah> barSet = barList.stream().map(Main::barToBlah).collect(toCollection(HashSet::new));

    barList.stream()
            .filter(bar -> !fooSet.contains(barToBlah(bar)))
            .forEach(System.out::println);
    fooList.stream()
            .filter(foo -> !barSet.contains(fooToBlah(foo)))
            .forEach(System.out::println);
}

static Blah fooToBlah(Foo foo) {
    return new Blah(foo.name, foo.age);
}

static Blah barToBlah(Bar bar) {
    return new Blah(bar.barName, "" + bar.codeBar);
}

static class Blah {
    String name;
    String age;

    public Blah(String name, String age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public boolean equals(Object o) {
        ...
    }

    @Override
    public int hashCode() {
        ...
    }
}
像这样的事情

barList.stream()
        .filter(bar -> fooList.stream()
                .map(Main::fooToBlah)
                .noneMatch(foo -> foo.equals(barToBlah(bar)))
        )
        .forEach(System.out::println);
甚至可以完全删除
Blah

barList.stream()
        .filter(bar -> fooList.stream().noneMatch(foo -> Objects.equals(foo.name, bar.barName) && Objects.equals(foo.age, "" + bar.codeBar)
        .forEach(System.out::println);

但最终的时间复杂度要差得多,而且还存在可读性问题。

一个简单的解决方案是在两个列表之间循环。假设您可以将等式条件表述为
BiPredicate

这就是时间复杂性

更好的解决方案是定义一个像
FooBarKey
这样的关键类,它将保存
name
age
并正确地实现
等于(…)
hashCode()
。然后,您可以执行以下操作:

Map<FooBarKey, List<Bar>> barsByKey = bars
    .stream()
    .collect(Collectors.groupingBy(
        FooBarKey::ofBar,
        HashMap::new,
        Collectors.toList()));

Set<FooBarKey> fooKeys = foos
    .stream()
    .map(FooBarKey::ofFoo)
    .collect(Collectors.toCollection(HashSet::new));

barsByKey.keySet().removeAll(fooKeys);

Set<Bar> uncommonBars = barsByKey
    .values()
    .stream()
    .flatMap(Collection::stream)
    .collect(Collectors.toSet());
Map barsByKey=bar
.stream()
.collect(收集器.groupingBy(
FooBarKey::of Bar,
HashMap::新建,
收藏家;
设置fooKeys=foos
.stream()
.map(FooBarKey::ofFoo)
.collect(Collectors.toCollection(HashSet::new));
barsByKey.keySet().removeAll(fookey);
设置不寻常项=barsByKey
.values()
.stream()
.flatMap(集合::流)
.collect(收集器.toSet());
关于解决方案的几点注意事项:

  • 我认为在这里创建
    Map
    是合理的,可以避免为相同的
    Bar
    s不断创建新的
    FooBarKey
    实例
  • 由于列表中可能有具有相同键的条,因此需要使用多映射
    map
  • HashMap::new
    HashSet::new
    供应商在适用的情况下用于确保使用哈希表来保证相应操作的
    O(1)

这应该是
O(2*n+m)

一个简单的解决方案是在两个列表中循环。假设您可以将等式条件表述为
BiPredicate

这就是时间复杂性

更好的解决方案是定义一个像
FooBarKey
这样的关键类,它将保存
name
age
并正确地实现
等于(…)
hashCode()
。然后,您可以执行以下操作:

Map<FooBarKey, List<Bar>> barsByKey = bars
    .stream()
    .collect(Collectors.groupingBy(
        FooBarKey::ofBar,
        HashMap::new,
        Collectors.toList()));

Set<FooBarKey> fooKeys = foos
    .stream()
    .map(FooBarKey::ofFoo)
    .collect(Collectors.toCollection(HashSet::new));

barsByKey.keySet().removeAll(fooKeys);

Set<Bar> uncommonBars = barsByKey
    .values()
    .stream()
    .flatMap(Collection::stream)
    .collect(Collectors.toSet());
Map barsByKey=bar
.stream()
.collect(收集器.groupingBy(
FooBarKey::of Bar,
HashMap::新建,
收藏家;
设置fooKeys=foos
.stream()
.map(FooBarKey::ofFoo)
.collect(Collectors.toCollection(HashSet::new));
barsByKey.keySet().removeAll(fookey);
设置不寻常项=barsByKey
.values()
.stream()
.flatMap(集合::流)
.collect(收集器.toSet());
关于解决方案的几点注意事项:

  • 我认为在这里创建
    Map
    是合理的,可以避免为相同的
    Bar
    s不断创建新的
    FooBarKey
    实例
  • 由于列表中可能有具有相同键的条,因此需要使用多映射
    map
  • HashMap::new
    HashSet::new
    供应商在适用的情况下用于确保使用哈希表来保证相应操作的
    O(1)

这应该是
O(2*n+m)
“建立它们之间的关系”到底是什么意思?我的意思是我们可以使用这些字段来比较并知道它们是否相等。您想如何将
字符串年龄
int codeBar
进行比较?他们永远不会平等。老实说,我建议您将一个类的对象转换为另一个类。在您的逻辑中,如果
age.equals(codeBar.toString())和&name.equals(barName)
,那么它们是相等的?age是一个字符串,但可以解析为整数,这并不重要,如果您愿意,我可以更改它。“建立它们之间的关系”是什么确切地说是什么意思?我的意思是我们可以使用这些字段来比较并知道它们是否相等。您想如何将
字符串年龄
int codeBar
进行比较?他们永远不会平等。老实说,我建议将一个类的对象转换为另一个类。在您的逻辑中,如果
age.equals(codeBar.toString())和&name.equals(barName)
,那么它们是相等的?age是一个字符串,但可以解析为整数,这并不重要,如果您愿意,我可以更改它。
Bar
需要实现
Comparable
,而
Foo
需要实现
Comparable
,这样才能工作,是吗?@KevinAnderson否,您不需要这里的
Comparable
。如果使用
TreeSet
,则需要此接口,但是,在这种情况下,这将比<代码> HASSET 有更坏的性能。我认为您没有考虑“<代码> FoO 和<代码> BAR <代码> >包含“当代码< > HASCODE 和<代码>等于 >代码> BAR 时,需要执行<代码>可比的< /代码>。而
Foo
需要实现
compariable
,这样才能起作用,是吗?@KevinAnder