根据多个'optional'条件过滤HashMap
Filter HashMap based on multiple 'optional' conditions
我有一个 HashMap 需要在函数中过滤:
public void filter(filterOption1, filterOption2, filterOption3, filterOption4) {
//Filter map in here
...
}
过滤器选项 filterOption1
、filterOption2
、filterOption3
、filterOption4
在运行时可能为空,而我希望避免的是类似的东西来自:
public void filter(filterOption1, filterOption2, filterOption3, filterOption4) {
if(filterOption1 != null && filterOption2 == null && filterOption3 == null && filterOption4 == null) {
// Filter map values on filterOption1
} else if(filterOption1 != null && filterOption2 != null && filterOption3 == null && filterOption4 == null) {
// Filter map values on filterOption1 and filterOption2
} else if ... // And so on
}
有没有什么方法可以通过 map.stream()
的一些巧妙过滤来避免链接 16 个 if 语句?
这是一种解决方案。它说明您不需要一系列 if 语句。
您可以通过向过滤器传递谓词集合来进一步改进。
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Predicate;
public class FilterOption {
public static void main(String... args) {
FilterOption f = new FilterOption();
System.out.println(f.theMap);
f.filter(null, null);
System.out.println(f.theMap);
f = new FilterOption();
f.filter(null, s -> s.startsWith("f"));
System.out.println(f.theMap);
}
public FilterOption() {
theMap.put("a", "foo");
theMap.put("b", "bar");
}
Map<String, String> theMap = new HashMap<>();
// assume we are filtering the values of the map
// and assume that we keep the key if no filter
// is false, and that a missing filter is true
public void filter(Predicate<String> filterOption1,
Predicate<String> filterOption2) {
List<Map.Entry<String, String>> entries =
new ArrayList(theMap.entrySet());
for (Map.Entry<String, String> entry : entries) {
if (!keep(entry.getValue(), filterOption1)
|| !keep(entry.getValue(), filterOption2)) {
theMap.remove(entry.getKey());
}
}
}
private boolean keep(String value, Predicate<String> filterOption) {
return filterOption == null || filterOption.test(value);
}
}
另一个解决方案,如果你能控制它,就是不传递 null。
如果您的方法希望获得某种过滤器,为什么要给它一个空值?这可以在调用方法中处理,如果它真的不想过滤任何东西,它应该传递一个身份函数而不是 null。
您可以创建一些接受 Predicate
s, concatenates non-null elements and produces a chain of Predicate
s. Then you can pass this chain to the filter
方法数组的方法:
public static void main(String... args) {
Map<Character, Character> map =
Map.of('a', 'A', 'b', 'B', 'c', 'C', 'd', 'D');
// predicate chain 'and'
Map<Character, Character> filtered1 = map.entrySet().stream()
.filter(predicateChain(Predicate::and,
e -> e.getKey() > 'a', null,
e -> e.getValue() < 'D', null))
.collect(Collectors.toMap(
Map.Entry::getKey, Map.Entry::getValue));
System.out.println(filtered1); // {b=B, c=C}
// predicate chain 'or'
Map<Character, Character> filtered2 = map.entrySet().stream()
.filter(predicateChain(Predicate::or,
e -> e.getKey() < 'b', null,
e -> e.getValue() > 'C', null))
.collect(Collectors.toMap(
Map.Entry::getKey, Map.Entry::getValue));
System.out.println(filtered2); // {a=A, d=D}
}
@SafeVarargs
public static <T> Predicate<T> predicateChain(
BinaryOperator<Predicate<T>> accumulator,
Predicate<T>... predicates) {
return Stream.of(predicates)
// non-null predicates
.filter(Objects::nonNull)
// concatenation of predicates
.reduce(accumulator)
.orElse(p -> true);
}
我有一个 HashMap 需要在函数中过滤:
public void filter(filterOption1, filterOption2, filterOption3, filterOption4) {
//Filter map in here
...
}
过滤器选项 filterOption1
、filterOption2
、filterOption3
、filterOption4
在运行时可能为空,而我希望避免的是类似的东西来自:
public void filter(filterOption1, filterOption2, filterOption3, filterOption4) {
if(filterOption1 != null && filterOption2 == null && filterOption3 == null && filterOption4 == null) {
// Filter map values on filterOption1
} else if(filterOption1 != null && filterOption2 != null && filterOption3 == null && filterOption4 == null) {
// Filter map values on filterOption1 and filterOption2
} else if ... // And so on
}
有没有什么方法可以通过 map.stream()
的一些巧妙过滤来避免链接 16 个 if 语句?
这是一种解决方案。它说明您不需要一系列 if 语句。
您可以通过向过滤器传递谓词集合来进一步改进。
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Predicate;
public class FilterOption {
public static void main(String... args) {
FilterOption f = new FilterOption();
System.out.println(f.theMap);
f.filter(null, null);
System.out.println(f.theMap);
f = new FilterOption();
f.filter(null, s -> s.startsWith("f"));
System.out.println(f.theMap);
}
public FilterOption() {
theMap.put("a", "foo");
theMap.put("b", "bar");
}
Map<String, String> theMap = new HashMap<>();
// assume we are filtering the values of the map
// and assume that we keep the key if no filter
// is false, and that a missing filter is true
public void filter(Predicate<String> filterOption1,
Predicate<String> filterOption2) {
List<Map.Entry<String, String>> entries =
new ArrayList(theMap.entrySet());
for (Map.Entry<String, String> entry : entries) {
if (!keep(entry.getValue(), filterOption1)
|| !keep(entry.getValue(), filterOption2)) {
theMap.remove(entry.getKey());
}
}
}
private boolean keep(String value, Predicate<String> filterOption) {
return filterOption == null || filterOption.test(value);
}
}
另一个解决方案,如果你能控制它,就是不传递 null。
如果您的方法希望获得某种过滤器,为什么要给它一个空值?这可以在调用方法中处理,如果它真的不想过滤任何东西,它应该传递一个身份函数而不是 null。
您可以创建一些接受 Predicate
s, concatenates non-null elements and produces a chain of Predicate
s. Then you can pass this chain to the filter
方法数组的方法:
public static void main(String... args) {
Map<Character, Character> map =
Map.of('a', 'A', 'b', 'B', 'c', 'C', 'd', 'D');
// predicate chain 'and'
Map<Character, Character> filtered1 = map.entrySet().stream()
.filter(predicateChain(Predicate::and,
e -> e.getKey() > 'a', null,
e -> e.getValue() < 'D', null))
.collect(Collectors.toMap(
Map.Entry::getKey, Map.Entry::getValue));
System.out.println(filtered1); // {b=B, c=C}
// predicate chain 'or'
Map<Character, Character> filtered2 = map.entrySet().stream()
.filter(predicateChain(Predicate::or,
e -> e.getKey() < 'b', null,
e -> e.getValue() > 'C', null))
.collect(Collectors.toMap(
Map.Entry::getKey, Map.Entry::getValue));
System.out.println(filtered2); // {a=A, d=D}
}
@SafeVarargs
public static <T> Predicate<T> predicateChain(
BinaryOperator<Predicate<T>> accumulator,
Predicate<T>... predicates) {
return Stream.of(predicates)
// non-null predicates
.filter(Objects::nonNull)
// concatenation of predicates
.reduce(accumulator)
.orElse(p -> true);
}