如何返回两个列表之间的差异?

Posted

技术标签:

【中文标题】如何返回两个列表之间的差异?【英文标题】:How can I return the difference between two lists? 【发布时间】:2015-01-16 03:31:46 【问题描述】:

我有两个数组列表,例如

List<Date> a;
contains : 10/10/2014, 10/11/2016

List<Date> b;
contains : 10/10/2016

如何在列表 ab 之间进行检查,以便返回 b 中缺少的值?例如10/10/2014

【问题讨论】:

guava 有一些不同的工具,但它适用于Set,我认为removeAll 可能适合你 复制列表a。从副本中删除所有出现在b 中的元素。 docs.oracle.com/javase/7/docs/api/java/util/… 如果你想要两者之间的析取,CollectionUtil 有一个析取方法可以返回差值。 这可能是指来自 Apache Commons Collections 的 CollectionUtils.subtract;有关详细信息,请参阅this answer。 【参考方案1】:

您可以将它们转换为Set 集合,并对它们执行集差操作。

像这样:

Set<Date> ad = new HashSet<Date>(a);
Set<Date> bd = new HashSet<Date>(b);
ad.removeAll(bd);

【讨论】:

removeAll 返回 boolean 而不是 Set 没错,但是当您查看文档时,您会看到此布尔值告知“此集合是否因调用而更改”。进行此更改后,您可以访问 Set,您会注意到它具有您预期的结果。 创建bd HashSet 是不必要的。您可以拨打ad.removeAll(b) 如果 bd 的元素比 ad 多怎么办?在那种情况下会发生什么?【参考方案2】:

如果你只想找到b中的缺失值,你可以这样做:

List toReturn = new ArrayList(a);
toReturn.removeAll(b);

return toReturn;

如果您想找出任一列表中存在的值,您可以执行上面的代码两次。使用更改的列表。

【讨论】:

如果它的列表不可修改怎么办? 由于您创建了一个新列表,这也适用于不可修改的列表。【参考方案3】:

我看起来很相似,但我想要两个列表中的差异(两个列表之间的不常见元素)。

假设我有:

List<String> oldKeys = Arrays.asList("key0","key1","key2","key5");
List<String> newKeys = Arrays.asList("key0","key2","key5", "key6");

我想知道添加了哪个键以及删除了哪个键,即我想获得(key1, key6)

使用org.apache.commons.collections.CollectionUtils

List<String> list = new ArrayList<>(CollectionUtils.disjunction(newKeys, oldKeys));

结果

["key1", "key6"]

【讨论】:

你能不能把我指向 maven 存储库。我试过这个https://mvnrepository.com/artifact/org.apache.commons/commons-collections4/4.4 但它似乎不是正确的。 @paradocslover 它是mvnrepository.com/artifact/commons-collections/… 非常感谢!!知道在新版本的包中重命名的函数是什么吗?【参考方案4】:

您可以在 Java 8 Stream 库中使用 filter

List<String> aList = List.of("l","e","t","'","s");
List<String> bList = List.of("g","o","e","s","t");

List<String> difference = aList.stream()
    .filter(aObject -> 
        return ! bList.contains(aObject);
      )
    .collect(Collectors.toList());

//more reduced: no curly braces, no return
List<String> difference2 = aList.stream()
    .filter(aObject -> ! bList.contains(aObject))
    .collect(Collectors.toList());

System.out.println(difference); 的结果:

[e, t, s]

【讨论】:

谢谢陌生人!【参考方案5】:

您可以使用 Apache Commons Collections 4.0 中的 CollectionUtils:

new ArrayList<>(CollectionUtils.subtract(a, b))

【讨论】:

注意:这种方法不以任何方式支持泛型,所以你得到的是一个原始的、未经检查的 Collection 实例。 方法签名是:public static &lt;O&gt; Collection&lt;O&gt; subtract(Iterable&lt;? extends O&gt; a, Iterable&lt;? extends O&gt; b),根据文档:“O - 能够表示两个输入集合中包含的类型的泛型类型。” 你确实是对的;过失。我正在查看该类的 3.2 版本,其中该方法具有简单的 public static Collection subtract(final Collection a, final Collection b) 签名。很高兴看到他们在 4.0 迭代中对此进行了改进。【参考方案6】:

首先将列表转换为集合。

// create an empty set 
Set<T> set = new HashSet<>(); 

// Add each element of list into the set 
for (T t : list) 
    set.add(t); 

您可以使用 Sets.difference(Set1, Set2),它返回 Set1 中存在的额外项目。 您可以使用Sets.difference(Set2, Set1),它会返回 Set2 中存在的额外项目。

【讨论】:

哇,不错的解决方案。我从来不知道这门课【参考方案7】:

使用 Stream API,您可以执行以下操作:

List<String> aWithoutB = a.stream()
    .filter(element -> !b.contains(element))
    .collect(Collectors.toList());

List<String> bWithoutA = b.stream()
    .filter(element -> !a.contains(element))
    .collect(Collectors.toList());

【讨论】:

【参考方案8】:

这里是这个问题的通用解决方案。

public <T> List<T> difference(List<T> first, List<T> second) 
    List<T> toReturn = new ArrayList<>(first);
    toReturn.removeAll(second);
    return toReturn;

【讨论】:

这在大多数情况下都会派上用场。谢谢!!【参考方案9】:
List<String> l1 = new ArrayList<String>();
l1.add("apple");
l1.add("orange");
l1.add("banana");
l1.add("strawberry");

List<String> l2 = new ArrayList<String>();
l2.add("apple");
l2.add("orange");

System.out.println(l1);
System.out.println(l2);

for (String A: l2) 
  if (l1.contains(A))
    l1.remove(A);


System.out.println("output");
System.out.println(l1);

输出:

[apple, orange, banana, strawberry]
[apple, orange]
output
[banana, strawberry]

【讨论】:

【参考方案10】:

您可以在underscore-java 库中调用Underscore.difference(lists) 方法。 Live example

import com.github.underscore.Underscore;
import java.util.Arrays;
import java.util.List;

public class Main 
    public static void main(String[] args) 
        List<Integer> list1 = Arrays.asList(1, 2, 3);
        List<Integer> list2 = Arrays.asList(1, 2);
        List<Integer> list3 = Underscore.difference(list1, list2);
        System.out.println(list3);
        // [3]
    

【讨论】:

如果 list2 还包含一些额外的值怎么办。 list2 = 1,2,4,5。预期列表 3 = 3,4,5【参考方案11】:

我一直在寻找一个不同的问题并遇到了这个问题,所以我将把我的解决方案添加到一个相关的问题:比较两个地图。

    // make a copy of the data
    Map<String,String> a = new HashMap<String,String>(actual);
    Map<String,String> e = new HashMap<String,String>(expected);
    // check *every* expected value
    for(Map.Entry<String, String> val : e.entrySet())
        // check for presence
        if(!a.containsKey(val.getKey()))
            System.out.println(String.format("Did not find expected value: %s", val.getKey()));
        
        // check for equality
        else
            if(0 != a.get(val.getKey()).compareTo(val.getValue()))
                System.out.println(String.format("Value does not match expected: %s", val.getValue()));
            
            // we have found the item, so remove it 
            // from future consideration. While it 
            // doesn't affect Java Maps, other types of sets
            // may contain duplicates, this will flag those
            // duplicates. 
            a.remove(val.getKey());
        
    
    // check to see that we did not receive extra values
    for(Map.Entry<String,String> val : a.entrySet())
        System.out.println(String.format("Found unexpected value: %s", val.getKey()));
    

它的工作原理与其他解决方案相同,但不仅比较存在的值,而且比较它们包含相同的值。在比较来自两个来源的数据(员工和经理输入的值匹配;客户和公司交易匹配;...等)时,我主要在会计软件中使用它

【讨论】:

我不知道有关地图的问题。如果您发现有关地图的问题,请随时链接到此答案。 答案应解决所提出的问题。如果您认为您有一个有用的代码 sn-p / 解释某些不存在问题的东西,请自己提出问题并使用内置的站点功能自行回答。不要在不相关的问题下发布您的答案。 我的回答和问题的区别不在于Map vs List的使用。不同之处在于仅要求缺失值的问题,我解决了值的“缺失、添加和相等”。如果寻求答案的人看不到 MapSetList 是相关概念的方式,我会担心。【参考方案12】:

Set 是下面的一个映射,我能够获得两个列表之间的差异,超过一百万个条目,每个条目都将其包装在一个 HashSet 中,这是一个简单的代码。

private List<String>notPresentMethod(final List<String>left,final List<String>right)
    final Set<String>setIsFaster = new HashSet<>(right);
    return left.stream()
            .filter(((Predicate<String>)setIsFaster::contains).negate())
            .collect(Collectors.toList());

仅使用列表需要一个多小时,但没有完成。使用此示例只需几秒钟。

【讨论】:

以上是关于如何返回两个列表之间的差异?的主要内容,如果未能解决你的问题,请参考以下文章

如何以毫秒为单位获得两个 QDateTimes 之间的差异?

使用python返回excel中两个不同文件中两列之间的差异

返回两个可枚举之间的差异

休眠 - 两个日期之间的差异

检查两个类列表之间的差异

如何使用 SQL 显示两个不同区域中时间戳之间的实时差异?