Java 可选地在流上应用过滤器
我正在尝试对对象列表执行“最佳匹配”。我想实现一个级联过滤器,目标是只得到一个最终成为“最佳匹配”的对象。我有一个ObjectA列表,还有一个ObjectB,我正在比较它的属性。如果有多个元素,有没有一种方法可以选择性地对流应用过滤器 目前我已经实现了如下:Java 可选地在流上应用过滤器,java,java-8,java-stream,Java,Java 8,Java Stream,我正在尝试对对象列表执行“最佳匹配”。我想实现一个级联过滤器,目标是只得到一个最终成为“最佳匹配”的对象。我有一个ObjectA列表,还有一个ObjectB,我正在比较它的属性。如果有多个元素,有没有一种方法可以选择性地对流应用过滤器 目前我已经实现了如下: List<ObjectA> listOfObjectA; ObjectB oB; List<ObjectA> matchedByProp1 = listOfObjectA.stream() .filt
List<ObjectA> listOfObjectA;
ObjectB oB;
List<ObjectA> matchedByProp1 = listOfObjectA.stream()
.filter(oA -> oB.getProp1().equals(oA.getProp1())).collect(Collectors.toList());
if (matchedByProp1.isEmpty()) {
// If no objects match, then return null
return null;
} else if (matchedByProp1.size() == 1) {
// If one object matches prop1, this is easy
return matchedByProp1.stream().findFirst().orElse(null);
}
// If more than one object is left, filter further by prop2
List<ObjectA> matchedByProp2 = matchedByProp1.stream()
.filter(oA -> oB.getProp2().equals(oA.getProp2()))
.collect(Collectors.toList());
if (matchedByProp2.isEmpty()) {
// If further filtering is not successful, return one from the previous set
return matchedByProp1.stream().findFirst().orElse(null);
} else if (matchedByProp2.size() == 1) {
// If one object matches prop2, this is easy
return matchedByProp2.stream().findFirst().orElse(null);
}
// If more than one object is left, filter further by prop3
List<ObjectA> matchedByProp3 = matchedByProp2.stream()
.filter(oA -> oB.getProp3().equals(oA.getProp3()))
.collect(Collectors.toList());
if (matchedByProp3.isEmpty()) {
// If further filtering is not successful, return one from the previous set
return matchedByProp2.stream().findFirst().orElse(null);
} else if (matchedByProp3.size() == 1) {
// If one object matches prop3, this is easy
return matchedByProp3.stream().findFirst().orElse(null);
}
// We still have too many options, just choose one
return matchedByProp3.stream().findFirst().orElse(null);
ObjectA match = listOfObjectA.stream()
.filter(oA -> oB.getProp1().equals(oA.getProp1()))
.optionallyFilter(oA -> oB.getProp2().equals(oA.getProp2()))
.optionallyFilter(oA -> oB.getProp3().equals(oA.getProp3()))
.getFirst().orElse(null);
我曾尝试按如下方式实现此方法,但遇到了一个问题,即我试图使用流两次
private class Matcher<T, U> {
private final U u;
private final Stream<T> stream;
public Matcher(U u) {
this.u = u;
stream = Stream.empty();
}
public Matcher(U u, Stream<T> stream) {
this.u = u;
this.stream = stream;
}
public Matcher<T, U> from(Stream<T> stream) {
return new Matcher<>(u, stream);
}
public Matcher<T, U> mustMatch(Function<T, Object> tProp, Function<U, Object> uProp) {
return new Matcher<>(u, stream.filter(t -> tProp.apply(t).equals(uProp.apply(u))));
}
public Matcher<T, U> shouldMatch(Function<T, Object> tProp, Function<U, Object> uProp) {
if (stream.filter(t -> tProp.apply(t).equals(uProp.apply(u))).count() > 0) {
return new Matcher<>(stream.filter(t -> tProp.apply(t).equals(uProp.apply(u))));
}
return this;
}
public Optional<T> get() {
return stream.findFirst();
}
}
ObjectA match = new Matcher<ObjectA, ObjectB>(oB, listOfObjectA.stream())
.mustMatch(ObjectA::getProp1, ObjectB::getProp1)
.shouldMatch(ObjectA::getProp2, ObjectB::getProp2)
.shouldMatch(ObjectA::getProp3, ObjectB::getProp3)
.get().orElse(null);
私有类匹配器{
私立大学;
私有最终流;
公共匹配器(U){
这个。u=u;
stream=stream.empty();
}
公共匹配器(U,流){
这个。u=u;
this.stream=流;
}
来自的公共匹配器(流){
返回新匹配器(u,流);
}
公共匹配器mustMatch(函数tProp、函数uProp){
返回新的匹配器(u,stream.filter(t->tProp.apply(t).equals(uProp.apply(u)));
}
公共匹配器应匹配(函数tProp、函数uProp){
if(stream.filter(t->tProp.apply(t).equals(uProp.apply(u))).count()>0){
返回新的匹配器(stream.filter(t->tProp.apply(t).equals(uProp.apply(u));
}
归还这个;
}
公共可选get(){
返回stream.findFirst();
}
}
ObjectA match=新匹配器(oB,listOfObjectA.stream())
.mustMatch(ObjectA::getProp1,ObjectB::getProp1)
.shouldMatch(ObjectA::getProp2,ObjectB::getProp2)
.shouldMatch(ObjectA::getProp3,ObjectB::getProp3)
.get().orElse(null);
现在我可以像现在一样在Matcher类中使用列表收集器,但似乎只是为了一个简单的条件,将流收集到列表中并重新流化,这似乎是不必要的。有更好的方法吗?请注意,在不同的使用中,可能会有不同的属性。据我所知,您的逻辑:
List<Predicate<ObjectA>> props = Arrays.asList(
oA -> oB.getProp1().equals(oA.getProp1()),
oA -> oB.getProp2().equals(oA.getProp2()),
oA -> oB.getProp3().equals(oA.getProp3()));
ObjectA previousChoice = null;
for(Predicate<ObjectA> p: props) {
listOfObjectA = listOfObjectA.stream().filter(p).collect(Collectors.toList());
if(listOfObjectA.isEmpty()) return previousChoice;
else {
previousChoice = listOfObjectA.get(0);
if(listOfObjectA.size() == 1) break;
}
}
return previousChoice;
List props=Arrays.asList(
oA->oB.getProp1().equals(oA.getProp1()),
oA->oB.getProp2().equals(oA.getProp2()),
oA->oB.getProp3().equals(oA.getProp3());
ObjectA previousChoice=null;
for(谓词p:props){
listOfObjectA=listOfObjectA.stream().filter(p.collect)(Collectors.toList());
if(listOfObjectA.isEmpty())返回上一个选项;
否则{
previousChoice=ListofObject.get(0);
如果(listOfObjectA.size()==1)中断;
}
}
返回先前的选择;
或没有溪流:
listOfObjectA = new ArrayList<>(listOfObjectA);
ObjectA previousChoice = null;
for(Predicate<ObjectA> p: props) {
listOfObjectA.removeIf(p.negate());
if(listOfObjectA.isEmpty()) return previousChoice;
else {
previousChoice = listOfObjectA.get(0);
if(listOfObjectA.size() == 1) break;
}
}
return previousChoice;
listOfObjectA=newarraylist(listOfObjectA);
ObjectA previousChoice=null;
for(谓词p:props){
删除对象列表(p.negate());
if(listOfObjectA.isEmpty())返回上一个选项;
否则{
previousChoice=ListofObject.get(0);
如果(listOfObjectA.size()==1)中断;
}
}
返回先前的选择;
这也可以被泛化以处理两种情况:
static ObjectB get(List<ObjectB> list, ObjectA oA) {
return get(list,
oB -> oA.getProp1().equals(oB.getProp1()),
oB -> oA.getProp2().equals(oB.getProp2()),
oB -> oA.getProp3().equals(oB.getProp3()));
}
static ObjectA get(List<ObjectA> list, ObjectB oB) {
return get(list,
oA -> oB.getProp1().equals(oA.getProp1()),
oA -> oB.getProp2().equals(oA.getProp2()),
oA -> oB.getProp3().equals(oA.getProp3()));
}
static <T> T get(List<T> listOfT, Predicate<T>... props) {
listOfT = new ArrayList<>(listOfT);
T previousChoice = null;
for(Predicate<T> p: props) {
listOfT.removeIf(p.negate());
if(listOfT.isEmpty()) return previousChoice;
else {
previousChoice = listOfT.get(0);
if(listOfT.size() == 1) break;
}
}
return previousChoice;
}
静态ObjectB获取(列表,ObjectA oA){
返回get(列表,
oB->oA.getProp1().equals(oB.getProp1()),
oB->oA.getProp2().equals(oB.getProp2()),
oB->oA.getProp3().equals(oB.getProp3());
}
静态ObjectA get(列表,ObjectB oB){
返回get(列表,
oA->oB.getProp1().equals(oA.getProp1()),
oA->oB.getProp2().equals(oA.getProp2()),
oA->oB.getProp3().equals(oA.getProp3());
}
静态T获取(列表ListSoft、谓词…道具){
ListSoft=新的ArrayList(ListSoft);
T previousChoice=null;
for(谓词p:props){
listOfT.removeIf(p.negate());
if(listOfT.isEmpty())返回previousChoice;
否则{
previousChoice=ListSoft.get(0);
如果(listSoft.size()==1)中断;
}
}
返回先前的选择;
}
虽然谓词看起来相同,但它们做的事情不同,假设
ObjectA
和ObjectB
没有定义这些属性的公共基类(否则就太简单了)。因此,这种重复是不可避免的。尝试在谓词中使用函数
委托对其进行更广泛的泛化,不太可能使代码更简单。据我所知,您的逻辑:
List<Predicate<ObjectA>> props = Arrays.asList(
oA -> oB.getProp1().equals(oA.getProp1()),
oA -> oB.getProp2().equals(oA.getProp2()),
oA -> oB.getProp3().equals(oA.getProp3()));
ObjectA previousChoice = null;
for(Predicate<ObjectA> p: props) {
listOfObjectA = listOfObjectA.stream().filter(p).collect(Collectors.toList());
if(listOfObjectA.isEmpty()) return previousChoice;
else {
previousChoice = listOfObjectA.get(0);
if(listOfObjectA.size() == 1) break;
}
}
return previousChoice;
List props=Arrays.asList(
oA->oB.getProp1().equals(oA.getProp1()),
oA->oB.getProp2().equals(oA.getProp2()),
oA->oB.getProp3().equals(oA.getProp3());
ObjectA previousChoice=null;
for(谓词p:props){
listOfObjectA=listOfObjectA.stream().filter(p.collect)(Collectors.toList());
if(listOfObjectA.isEmpty())返回上一个选项;
否则{
previousChoice=ListofObject.get(0);
如果(listOfObjectA.size()==1)中断;
}
}
返回先前的选择;
或没有溪流:
listOfObjectA = new ArrayList<>(listOfObjectA);
ObjectA previousChoice = null;
for(Predicate<ObjectA> p: props) {
listOfObjectA.removeIf(p.negate());
if(listOfObjectA.isEmpty()) return previousChoice;
else {
previousChoice = listOfObjectA.get(0);
if(listOfObjectA.size() == 1) break;
}
}
return previousChoice;
listOfObjectA=newarraylist(listOfObjectA);
ObjectA previousChoice=null;
for(谓词p:props){
删除对象列表(p.negate());
if(listOfObjectA.isEmpty())返回上一个选项;
否则{
previousChoice=ListofObject.get(0);
如果(listOfObjectA.size()==1)中断;
}
}
返回先前的选择;
这也可以被泛化以处理两种情况:
static ObjectB get(List<ObjectB> list, ObjectA oA) {
return get(list,
oB -> oA.getProp1().equals(oB.getProp1()),
oB -> oA.getProp2().equals(oB.getProp2()),
oB -> oA.getProp3().equals(oB.getProp3()));
}
static ObjectA get(List<ObjectA> list, ObjectB oB) {
return get(list,
oA -> oB.getProp1().equals(oA.getProp1()),
oA -> oB.getProp2().equals(oA.getProp2()),
oA -> oB.getProp3().equals(oA.getProp3()));
}
static <T> T get(List<T> listOfT, Predicate<T>... props) {
listOfT = new ArrayList<>(listOfT);
T previousChoice = null;
for(Predicate<T> p: props) {
listOfT.removeIf(p.negate());
if(listOfT.isEmpty()) return previousChoice;
else {
previousChoice = listOfT.get(0);
if(listOfT.size() == 1) break;
}
}
return previousChoice;
}
静态ObjectB获取(列表,ObjectA oA){
返回get(列表,
oB->oA.getProp1().equals(oB.getProp1()),
oB->oA.getProp2().equals(oB.getProp2()),
oB->oA.getProp3().equals(oB.getProp3());
}
静态ObjectA get(列表,ObjectB oB){
返回get(列表,
oA->oB.getProp1().equals(oA.getProp1()),
oA->oB.getProp2().equals(oA.getProp2()),
oA->oB.getProp3().equals(oA.getProp3());
}
静态T获取(列表ListSoft、谓词…道具){
ListSoft=新的ArrayList(ListSoft);
T previousChoice=null;
for(谓词p:props){
listOfT.removeIf(p.negate());
if(listOfT.isEmpty())返回previousChoice;
否则{
previousChoice=ListSoft.get(0);