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