Skip to content

java8 请获取两个list差值

在Java 8中获取两个List<String>的差值,主要有几种常见场景:

1. 获取 list1 中有而 list2 中没有的元素(差集)

java
import java.util.*;
import java.util.stream.Collectors;

public class ListDifference {
    public static void main(String[] args) {
        List<String> list1 = Arrays.asList("A", "B", "C", "D", "E");
        List<String> list2 = Arrays.asList("B", "D", "F", "G");
      
        // 方法1:使用 Stream API(推荐)
        List<String> difference1 = list1.stream()
            .filter(item -> !list2.contains(item))
            .collect(Collectors.toList());
        System.out.println("list1 - list2: " + difference1);
        // 输出: [A, C, E]
      
        // 方法2:使用 HashSet(性能更好,适合大数据量)
        Set<String> set2 = new HashSet<>(list2);
        List<String> difference2 = list1.stream()
            .filter(item -> !set2.contains(item))
            .collect(Collectors.toList());
        System.out.println("list1 - list2: " + difference2);
      
        // 方法3:使用 removeAll
        List<String> copy1 = new ArrayList<>(list1);
        copy1.removeAll(list2);
        System.out.println("list1 - list2: " + copy1);
    }
}

2. 获取两个列表的对称差集(两个列表互不包含的元素)

java
public class SymmetricDifference {
    public static void main(String[] args) {
        List<String> list1 = Arrays.asList("A", "B", "C", "D", "E");
        List<String> list2 = Arrays.asList("B", "D", "F", "G");
      
        // 方法1:合并两个差集
        Set<String> set1 = new HashSet<>(list1);
        Set<String> set2 = new HashSet<>(list2);
      
        List<String> symmetricDiff = new ArrayList<>();
        // 添加 list1 有 list2 没有的
        symmetricDiff.addAll(list1.stream()
            .filter(item -> !set2.contains(item))
            .collect(Collectors.toList()));
        // 添加 list2 有 list1 没有的
        symmetricDiff.addAll(list2.stream()
            .filter(item -> !set1.contains(item))
            .collect(Collectors.toList()));
      
        System.out.println("对称差集: " + symmetricDiff);
        // 输出: [A, C, E, F, G]
      
        // 方法2:使用 HashSet 的对称差操作
        Set<String> difference = new HashSet<>(list1);
        difference.addAll(list2);  // 并集
        Set<String> intersection = new HashSet<>(list1);
        intersection.retainAll(list2);  // 交集
        difference.removeAll(intersection);  // 并集 - 交集 = 对称差集
      
        System.out.println("对称差集: " + new ArrayList<>(difference));
    }
}

3. 考虑重复元素的差值

java
public class DifferenceWithDuplicates {
    public static void main(String[] args) {
        List<String> list1 = Arrays.asList("A", "A", "B", "C", "C", "D");
        List<String> list2 = Arrays.asList("A", "B", "B", "D");
      
        // 创建可修改的副本
        List<String> list1Copy = new ArrayList<>(list1);
        List<String> list2Copy = new ArrayList<>(list2);
      
        // 移除交集元素
        for (String item : list2) {
            list1Copy.remove(item);
        }
      
        System.out.println("考虑重复的差集 (list1 - list2): " + list1Copy);
        // 输出: [A, C, C]
      
        // 使用 Map 统计计数
        Map<String, Long> count1 = list1.stream()
            .collect(Collectors.groupingBy(s -> s, Collectors.counting()));
        Map<String, Long> count2 = list2.stream()
            .collect(Collectors.groupingBy(s -> s, Collectors.counting()));
      
        List<String> result = new ArrayList<>();
        for (Map.Entry<String, Long> entry : count1.entrySet()) {
            String key = entry.getKey();
            Long countIn2 = count2.getOrDefault(key, 0L);
            long diff = entry.getValue() - countIn2;
            if (diff > 0) {
                for (int i = 0; i < diff; i++) {
                    result.add(key);
                }
            }
        }
      
        System.out.println("考虑重复的差集 (list1 - list2): " + result);
        // 输出: [A, C, C]
    }
}

4. 使用 Guava 库(更简洁)

java
import com.google.common.collect.Sets;
import com.google.common.collect.Lists;

public class GuavaDifference {
    public static void main(String[] args) {
        List<String> list1 = Arrays.asList("A", "B", "C", "D", "E");
        List<String> list2 = Arrays.asList("B", "D", "F", "G");
      
        // 差集
        Sets.SetView<String> difference = Sets.difference(
            new HashSet<>(list1), 
            new HashSet<>(list2)
        );
        System.out.println("list1 - list2: " + difference);
      
        // 对称差集
        Sets.SetView<String> symmetricDiff = Sets.symmetricDifference(
            new HashSet<>(list1), 
            new HashSet<>(list2)
        );
        System.out.println("对称差集: " + symmetricDiff);
    }
}

性能建议:

  1. 对于小数据集:使用 stream().filter() 即可
  2. 对于大数据集:先将 list2 转换为 HashSet 以提高 contains() 的性能
  3. 需要考虑顺序:使用 LinkedHashSetArrayList
  4. 考虑重复元素:需要使用计数方法

根据你的具体需求选择合适的实现方式。

耕书屋