我有两个清单。
list1
包含一些城市。
list2
包含城市的子列表。每个子列表包含一个人已经访问过的城市(一个子列表=一个人访问过的城市)。在示例中,Person1 去过罗马、阿姆斯特丹和维也纳,Person2 去过阿姆斯特丹、巴塞罗那和米兰...
我想知道有多少人去过第一个列表中的城市。不应出现重复计算。所以如果Person1已经从
list1
到过两个城市,就只算一次。
我想使用 Java Stream API 来实现这一点。有谁知道我该怎么做?
list1 = ["Barcelona", "Milan", "Athens"];
list2 = [["Rome", "Amsterdam", "Vienna"], ["Amsterdam", "Barcelona", "Milan"], ["Paris", "Athens"], ["Istanbul", "Barcelona", "Milan", "Athens"]];
//The expected result for this example is: 3
//Both lists already result from a stream (Collectors.toList())
你可以尝试这样的事情:
private static final List<String> CITIES = List.of("Barcelona", "Milan", "Athens");
private static final List<List<String>> VISITED_CITIES = List.of(
List.of("Rome", "Amsterdam", "Vienna"),
List.of("Amsterdam", "Barcelona", "Milan"),
List.of("Paris", "Athens"),
List.of("Instabul", "Barcelon", "Milan", "Athens")
);
public static void main(String... args) {
var count = VISITED_CITIES
.stream()
.flatMap(visited -> visited.stream().filter(CITIES::contains))
.distinct()
.count();
System.out.println(count);
}
通过此迭代,您将获得预期结果 3。但是,您可以修改代码以也收集到将显示频率的
Map
中(如果删除 distinct
中间步骤),如下所示:
var count = VISITED_CITIES
.stream()
.flatMap(visited -> visited.stream().filter(CITIES::contains))
.collect(Collectors.groupingBy(Function.identity()));
看看
mapToInt()
和 sum()
函数。
List<String> list1 = List.of("Barcelona", "Milan", "Athens");
List<List<String>> list2 = List.of(List.of("Rom", "Amsterdam", "Vienna"),
List.of("Amsterdam", "Barcelona", "Milan"),
List.of("Prais", "Athens"),
List.of("Istanbul", "Barcelona", "Milan", "Athens"));
int result = list2.stream().mapToInt(person -> person.stream().anyMatch(list1::contains) ? 1 : 0).sum();
我在这里所做的是创建一个所有人的流,然后将每个人映射到 1 或 0,具体取决于他们访问过的国家/地区是否包含在 list1 中。
这与以下 for 循环示例相同:
int result = 0;
for (List<String> person : list2)
{
int i = 0;
for (String visited : person)
{
if (list1.contains(visited))
{
i = 1;
break;
}
}
result += i;
}
long count = list2.stream()
.filter(c -> !Collections.disjoint(list1, c))
.count();
这会迭代每个人的城市列表,仅过滤掉去过第一个列表中城市的人,然后返回剩余过滤元素的计数。