我有一个类型的有效值列表:
Set<String> validTypes = ImmutableSet.of("TypeA", "TypeB", "TypeC");
我要从给定列表中提取具有有效类型的第一个值。在这种情况下,我会写这种东西:
public class A{
private String type;
private String member;
}
List<A> classAList;
classAList.stream()
.filter(a -> validTypes.contains(a.getType()))
.findFirst();
但是,我希望优先使用TypeA
,即如果classAList
具有TypeA
和TypeB
,我希望对象具有typeA
。为此,我要做的是:
Set<String> preferredValidTypes = ImmutableSet.of("TypeA");
classAList.stream()
.filter(a -> preferredValidTypes.contains(a.getType()))
.findFirst()
.orElseGet(() -> {
return classAList.stream()
.filter(a -> validTypes.contains(a.getType()))
.findFirst();
}
有没有更好的方法?
答案 0 :(得分:4)
按类型过滤列表,按类型排序,收集到列表,然后只获取第一个元素
List<A> collect = classAList.stream()
.filter(a -> validTypes.contains(a.getType()))
.sorted(Comparator.comparing(A::getType))
.collect(Collectors.toList());
System.out.println(collect.get(0));
答案 1 :(得分:2)
您可以使用自定义比较器,例如:
Comparator<A> comparator = (o1, o2) -> {
if (preferredValidTypes.contains(o1.getType()) && !preferredValidTypes.contains(o2.getType())) {
return 1;
} else if (!preferredValidTypes.contains(o1.getType()) && preferredValidTypes.contains(o2.getType())) {
return -1;
} else {
return 0;
}
};
对列表进行排序,然后根据需要从列表中findFirst
进行排序。
答案 2 :(得分:1)
我不喜欢使用Comparator给出的答案。排序是一项昂贵的操作。您可以步行浏览列表。找到首选值后,您就可以突破该值,否则就继续寻找有效值。
在这种情况下,anyMatch可以提供从流处理中突围的可能性:
MyVerifier verifier=new MyVerifier(validTypes,preferredValidTypes);
classAList.stream()
.anyMatch(verifier);
System.out.println("Preferred found:"+verifier.preferred);
System.out.println("Valid found:"+verifier.valid);
public static class MyVerifier implements Predicate<A> {
private Set<String> validTypes;
private Set<String> preferredValidTypes;
A preferred=null;
A valid=null;
public MyVerifier(Set<String> validTypes, Set<String> preferredValidTypes) {
super();
this.validTypes = validTypes;
this.preferredValidTypes = preferredValidTypes;
}
@Override
public boolean test(A a) {
if(preferred==null && preferredValidTypes.contains(a.getType())) {
preferred=a;
// we can stop because we found the first preferred
return true;
} else if(valid==null && validTypes.contains(a.getType())) {
valid=a;
}
return false;
}
}
答案 3 :(得分:1)
当然可以定义两个列表,一个具有所有有效类型,而一个具有首选类型。
但是,这是另一种方法。定义一个列表,或者实际上是一个Map
,其中键是有效类型,布尔值是该类型是否是首选类型。
Map<String, Boolean> validTypes = ImmutableMap.of(
"TypeA", false,
"TypeB", false,
"TypeC", true
);
AtomicReference
以下是一个选项:
AtomicReference<A> ref = new AtomicReference<>();
listOfAs.stream()
.filter(t -> validTypes.containsKey(t.getType()))
.anyMatch(t -> validTypes.get(ref.updateAndGet(u -> t).getType()));
AtomicReference
现在包含首选的A
(如果可用)或另一个有效的A
,或者如果流为空,则它包含null
。如果找到具有首选类型的A
,则此流操作会短路。
该选项的缺点是它会产生副作用,which is discouraged。
distinct()
另一个建议如下。它使用相同的映射结构,并使用布尔值表示首选的值。但是,它不会产生副作用。
Map<Boolean, A> map = listOfAs.stream()
.filter(t -> validTypes.containsKey(t.getType()))
.map(t -> new Carrier<>(validTypes.get(t.getType()), t))
.distinct()
.limit(2)
.collect(Collectors.toMap(Carrier::getKey, Carrier::getValue));
它的工作原理如下。
filter
丢弃所有无效类型的元素。Carrier<Boolean, A>
实例。 Carrier
是Map.Entry<K, V>
,仅实现equals
的{{1}}和hashCode
方法; key
无关紧要。这对于下一步是必要的,value
,它丢弃所有重复的元素。这样,只能找到一种首选类型,而只有一种有效类型。地图现在包含以下元素:
distinct()
=> Boolean.TRUE
(首选类型)A
=> Boolean.FALSE
具有有效类型使用检索适当的元素
A
答案 4 :(得分:0)
那么您必须要考虑到排序是稳定,即相等的元素将以与原始来源相同的顺序出现-您需要先正确获得满足您要求的df['string'] = df['string'].str.split(' ').map(lambda x: ' '.join(sorted(x)))
中的元素,因此:
List<A>
答案 5 :(得分:0)
如果您在其他集合中有首选的有效类型,则可以遵循此代码。
Map<String,A> groupByType = classAList
.stream()
/* additional filter to grouping by valid types.*/
//.filter(a->validTypes.contains(a.getType()))
.collect(Collectors.toMap(A::getType, Function.identity(),(v1, v2)->v1));
然后使用:
A result = preferredValidTypes
.stream()
.map(groupByType::get)
.findFirst()
.orElseThrow(RuntimeException::new);
或仅按首选有效类型分组
A result2 = classAList
.stream()
.filter(a -> preferredValidTypes.contains(a.getType()))
.collect(Collectors.toMap(A::getType, Function.identity(), (v1, v2) -> v1))
.entrySet()
.stream()
.findFirst()
.map(Map.Entry::getValue)
.orElseThrow(RuntimeException::new);
答案 6 :(得分:0)
在 Java8 中,您可以使用流:
public static Carnet findByCodeIsIn(Collection<Carnet> listCarnet, String codeIsIn) {
return listCarnet.stream().filter(carnet -> codeIsIn.equals(carnet.getCodeIsin())).findFirst().orElse(null);
}
此外,如果您有许多不同的对象(不仅是Carnet
),或者想通过不同的属性(不仅是cideIsin
查找它,还可以构建一个实用程序类来封装其中的逻辑:
public final class FindUtils {
public static <T> T findByProperty(Collection<T> col, Predicate<T> filter) {
return col.stream().filter(filter).findFirst().orElse(null);
}
}
public final class CarnetUtils {
public static Carnet findByCodeTitre(Collection<Carnet> listCarnet, String codeTitre) {
return FindUtils.findByProperty(listCarnet, carnet -> codeTitre.equals(carnet.getCodeTitre()));
}
public static Carnet findByNomTitre(Collection<Carnet> listCarnet, String nomTitre) {
return FindUtils.findByProperty(listCarnet, carnet -> nomTitre.equals(carnet.getNomTitre()));
}
public static Carnet findByCodeIsIn(Collection<Carnet> listCarnet, String codeIsin) {
return FindUtils.findByProperty(listCarnet, carnet -> codeIsin.equals(carnet.getCodeIsin()));
}
}