要明确我没有任何问题,并且真的不需要帮助,但无论如何我想问:
我们说我们有一个String数组
String[] sarr = new String[]{"POTATO", "TOMATO"};
我们有一个枚举
public enum Food{POTATO, TOMATO, PIZZA}
如果我想检查sarr
中Food
中是否存在所有字符串,请执行以下操作:
ArrayList<String> foodstrings = new ArrayList<>();
Arrays.asList(Food.values()).forEach((in) -> foodstrings.add(in.toString()));
if (!foodstrings.containsAll(Arrays.asList(sarr))) doStuff();
有没有办法在更少的代码行中执行此操作?或者只是一种更优雅的方式?
答案 0 :(得分:6)
您想确定数组中的所有元素是否都包含在食物名称列表中。
一种可能的解决方案是将食物名称转换为Set
(具有O(1)contains
);那么,我们需要确定数组中的所有元素是否都包含在这个集合中:
public static void main(String[] args) {
String[] sarr = new String[]{"POTATO", "TOMATO"};
Set<String> set = Arrays.stream(Food.values()).map(Enum::name).collect(Collectors.toSet());
boolean result = Arrays.stream(sarr).allMatch(set::contains);
}
在您当前的解决方案中,您使用forEach
改变外部变量,这是一种不好的做法。
答案 1 :(得分:4)
我相信前两行的更好版本是:
app:layout_behavior
使用Set<String> foodstrings = Arrays.stream(Food.values()).map(Enum::name).collect(Collectors.toSet());
代替Set
可以提高List
的效果,代码完全流式传输,而不是使用containsAll
和外部收集器。
forEach
仍然很好,虽然您可以将它们全部合并到一个语句中(格式化为可读性):
if
答案 2 :(得分:0)
if (Stream.of(sarr).allMatch(s -> Stream.of(Food.values()).anyMatch(t -> s.equals(t.name()))))
{
// all match
}
sarr
创建一个流(可以是适用于Java 1.8中引入的Collection
API的任何Stream
个对象。allMatch
,如果true
(即返回true / false的函数),则只返回Predicate
。Predicate
期望的allMatch
,我们提供了一个lambda,它通过流迭代第二组对象,并调用anyMatch
:一个简单的Predicate
如果任何成员对象满足提供的条件(再次,布尔函数),则返回true。anyMatch
提供了另一个lambda,它通过equals
实现来比较2个集合的成员。 此解决方案在语义上等同于不变
A \subset B
在我们的案例中是
sarr \subset Food.values()
和以下Java&lt; 1.8如下所示的代码,带有短路模拟规范(减去流开销):
// assume success, since if both sets are empty the invariant holds
boolean subset = true;
for (String a : sarr)
{
if (null == a) continue;
boolean contained = false;
for (Food b : Food.values())
if (b.name().equals(a)) { contained = true; break; }
if (!contained) { subset = false; break; }
}
if (subset)
{
// all match
}
当然,您可以替换不同的集合类型和条件,以及使用parallelStream()
来更好地利用可用的硬件。