在两个嵌套列表中查找公共元素的计数

Find the Count of common elements within the two nested Lists

提问人:impstuffsforcse 提问时间:8/1/2022 最后编辑:Alexander Ivanchenkoimpstuffsforcse 更新时间:8/2/2022 访问量:275

问:

在 Java 中将字符串列表 object1 中存在的每个元素与另一个对象 object2 进行比较

我有一个初始化为 object1 的字符串列表列表,如下所述:

List<List<String>> object1 = Arrays.asList(Arrays.asList("A", "B", "C"),
                                       Arrays.asList("D", "E", "F"), 
                                       Arrays.asList("G", "H", "I"));

我有另一个初始化为 object2 的字符串列表列表,如下所述:

List<List<String>> object2 = Arrays.asList(Arrays.asList("A", "B", "C"),
                                       Arrays.asList("D", "E", "F"), 
                                       Arrays.asList("G", "H", "J"));

如何以相同的顺序逐个比较两个对象之间的每个元素

需要初始化一个计数器变量来跟踪两个对象之间存在的公共元素的数量。

预期结果:8

Java 列表 比较 嵌套列表

评论

0赞 8/1/2022
您需要的结果/输出是什么?如果两个对象都以相同的顺序包含相同的元素,您是否只想要一个布尔值?因为在这种情况下,只需使用 equals 方法就足够了。PS:您的对象是名为“object1”的机器人
0赞 impstuffsforcse 8/1/2022
我也需要使用 count 变量来计算两个对象之间存在的公共元素的计数
0赞 impstuffsforcse 8/1/2022
对不起,让我编辑问题 - 它的两个不同的对象
0赞 8/1/2022
因此,您的示例的结果应该是因为前 2 个列表相等,还是因为前 2 个相等列表包含 6 个元素?26
0赞 impstuffsforcse 8/1/2022
计数应为 8(只有最后一个元素不同)

答:

2赞 user6073886 8/1/2022 #1

要获得所需的输出,最简单的方法是使用 2 个嵌套循环遍历 Lists 和 Sublists,并使用简单的计数器变量来跟踪相等的元素,检查每个元素是否相等:

int equalElements = 0;
for (int i = 0; i < object1.size() && i < object2.size(); i++) {
    final List<String> subList1 = object1.get(i);
    final List<String> subList2 = object2.get(i);
    for(int x = 0; x < subList1.size() && x < subList2.size(); x++) {
        if (Objects.equals(subList1.get(x), subList2.get(x))) {
            equalElements++;
        }
    }
}
    
System.out.println(equalElements);

评论

0赞 impstuffsforcse 8/1/2022
在if条件下存在的“对象”是什么?
0赞 8/1/2022
java.util.Objects - Java 7 中引入的辅助类,其中包含许多静态辅助工具方法。你也可以这样做,但这会抛出一个以防万一返回.static 方法也可以处理这些 null 情况,而不会引发异常。简而言之,这只是一种空安全的方式subList1.get(x).equals(subList2.get(x));NullPointerExceptionsubList1.get(x)nullObjects.equalsObjects.equals(subList1.get(x), subList2.get(x))subList1.get(x).equals(subList2.get(x));
3赞 Alexander Ivanchenko 8/2/2022 #2

您可以生成一个表示两个列表的列表中每个元素的出现次数。Map

然后,通过选择每对中的最小值,将与两个频率图中存在的相关的相加。

如果你对流感到满意,这个逻辑可以这样实现:

public static Map<String, Long> getFrequencies(List<List<String>> list) {
    
    return list.stream()
        .flatMap(List::stream)
        .collect(Collectors.groupingBy(
            Function.identity(),
            Collectors.counting()
        ));
}

public static long countCommonValues(Map<String, Long> map1, Map<String, Long> map2) {
    
    return map1.entrySet().stream()
        .filter(entry -> map2.containsKey(entry.getKey()))
        .mapToLong(entry -> Math.min(entry.getValue(), map2.get(entry.getKey())))
        .sum();
}

main()

public static void main(String[] args) {
    List<List<String>> list1 = List.of(
        List.of("A", "B", "A"),
        List.of("D", "E", "H"),
        List.of("G", "H", "I"));
    
    List<List<String>> list2 = List.of(
        List.of("A", "B", "C", "D"),
        List.of("D", "E", "F", "A"),
        List.of("G", "H", "J", "H"));

    System.out.println(countCommonValues(getFrequencies(list1), getFrequencies(list2)));
}

输出:

8   // "A", "A", "B", "D", "E", "G", "H", "H"

在线演示链接


如果顺序很重要并且嵌套列表不能保证大小相同,我们可以将两个列表展平,然后在相应的索引处比较元素。

public static <T> long countCommonValues(List<List<T>> list1, List<List<T>> list2) {
    
    List<T> flattened1 = flatten(list1);
    List<T> flattened2 = flatten(list2);
    
    return IntStream.range(0, Math.min(flattened1.size(), flattened2.size()))
        .filter(i -> flattened1.get(i).equals(flattened2.get(i)))
        .count();
}

public static <T> List<T> flatten(List<List<T>> list) {
    return list.stream()
        .flatMap(List::stream)
        .toList();
}

评论

0赞 Abe 8/2/2022
我们可以在 filter() 之后使用 count() 吗,因为 filter 获取了两个映射中的所有公共键?
0赞 Alexander Ivanchenko 8/2/2022
@yulinxp 你试过了吗?您可以,但结果不正确,此流不计算条目。
0赞 Abe 8/2/2022
是的,我试过了。它似乎对我有用。
0赞 Alexander Ivanchenko 8/2/2022
@yulinxp 我忘记了我使用了 OP 提供的测试用例。其中所有值都是唯一的,但情况可能并非如此。当存在多个相同元素时,需要映射,将相加,即出现次数。你明白了吗?sum()
0赞 Alexander Ivanchenko 8/2/2022
如果存在重复的元素,@yulinxp将失败。count()