Java比较两个List的对象值?

Posted

技术标签:

【中文标题】Java比较两个List的对象值?【英文标题】:Java Compare Two List's object values? 【发布时间】:2013-04-18 22:22:50 【问题描述】:

我有两个列表 **ListA<MyData> listA = new ArrayList<MyData>()** 和 ListB<MyData> listB = new ArrayList<MyData>() 都包含 MyData 类型的对象,而 MyData 包含这些变量。

MyData 
    String name;
    boolean check;
 

ListA 和 ListB 都包含 MyData 对象,现在我必须在这里比较列表的对象值 name 以及 check 变量,例如 if ListA 包含这些对象值

ListA = ["Ram",true],["Hariom",true],["Shiv",true];

和 ListB 也包含

ListB = ["Ram",true],["Hariom",true],["Shiv",true];

然后我必须比较列表并返回 false,因为两个列表相同 但如果 ListA 包含

ListA = ["Ram",true],["Hariom",true],["Shiv",false];

ListB包含

 ListB = ["Ram",true],["Hariom",true],["Shiv",true];

然后我必须比较列表并返回 true,因为两个列表不相同

或反之亦然,因此任何列表值的任何细微变化都必须返回 true。 我必须在这里提到的一件事,对象可以按任何顺序排列。

【问题讨论】:

我无法区分上述任何一个列表。 对象值被改变一个对象包含真另一个假 @askkuber 你是否关心两个列表的顺序,例如应该迭代它们总是给出相同的结果吗?如果没有,只需使用Set<MyData>,例如HashSet, implement equals() and hashCode() on MyData 并将两组与 setA.equals(setB) 进行比较。 @Philipp 列表包含任何顺序的对象,我必须比较它们并在发现任何单个更改时返回 true 我建议通过一个好的 hashCode() 实现对它们进行排序,然后比较成对的元素,看看它们是否相等。 【参考方案1】:

这不是最有效的解决方案,但最简洁的代码是:

boolean equalLists = listA.size() == listB.size() && listA.containsAll(listB);

更新:

@WesleyPorter 是对的。如果集合中有重复的对象,上述解决方案将不起作用。 要获得完整的解决方案,您需要对集合进行迭代,以便正确处理重复的对象。

private static boolean cmp( List<?> l1, List<?> l2 ) 
    // make a copy of the list so the original list is not changed, and remove() is supported
    ArrayList<?> cp = new ArrayList<>( l1 );
    for ( Object o : l2 ) 
        if ( !cp.remove( o ) ) 
            return false;
        
    
    return cp.isEmpty();

2014 年 10 月 28 日更新:

@RoeeGavriel 是对的。 return 语句必须是有条件的。以上代码已更新。

【讨论】:

此解决方案不适用于某些极端情况。例如,如果 listA = ["1", "blah", "1", "4"] 和 listB = ["1", "blah", "blah", "4"],则该方法将返回 true,当这两个列表确实不同。 如果 L1 拥有 L2 的所有项目以及更多项目(L1="1","2","3" & L2="1","2"),则更新将失败并返回 true .如果您将最后一条语句更改为return (cp.size()==0);,它将起作用 时间复杂度:O(n^2) ! 对于更复杂的 java 对象,我们是否需要覆盖 hashcode() 才能使其工作?【参考方案2】:

ArrayList 已经支持此功能,使用 equals 方法。引用the docs

... 换句话说,如果两个列表以相同的顺序包含相同的元素,则它们被定义为相等。

它确实需要您在 MyData 类中正确实现 equals

编辑

您已更新问题,指出列表可能有不同的顺序。在这种情况下,请先对列表进行排序,然后应用等于。

【讨论】:

他的一个要求是对象可以是任意顺序 是的,它现在这么说。但不是当我写答案时。 这是最好的答案! 这在我overwrite对象中的equals方法之后起作用【参考方案3】:

我得到了解决上述问题的方法

public boolean compareLists(List<MyData> prevList, List<MyData> modelList) 
        if (prevList.size() == modelList.size()) 
            for (MyData modelListdata : modelList) 
                for (MyData prevListdata : prevList) 
                    if (prevListdata.getName().equals(modelListdata.getName())
                            && prevListdata.isCheck() != modelListdata.isCheck()) 
                        return  true;

                    
                

            
        
        else
            return true;
        
        return false; 

    

已编辑:- 我们怎么能覆盖这个... 想象一下,如果你有两个数组“A”,真“B”,真“C”,真和“A”,真“B”,真“D”,真。即使数组 1 有 C 并且数组 2 有 D 也没有检查会发现(@Patashu 提到)..所以我做了以下更改。

public boolean compareLists(List<MyData> prevList, List<MyData> modelList) 
        if (prevList!= null && modelList!=null && prevList.size() == modelList.size()) 
            boolean indicator = false;
            for (MyData modelListdata : modelList) 
                for (MyData prevListdata : prevList) 
                    if (prevListdata.getName().equals(modelListdata.getName())
                            && prevListdata.isCheck() != modelListdata.isCheck()) 
                        return  true;

                    
                    if (modelListdata.getName().equals(prevListdata.getName())) 
                        indicator = false;
                        break;
                     else
                        indicator = true;
                
                

            
        if (indicator)
            return true;
    
        
        else
            return true;
        
        return false; 

    

【讨论】:

如果列表具有相同的对象但无序,这将不起作用。 @Patashu 未测试,但它会工作,因为我有两个 for 循环 只要列表始终具有相同的名称,您的算法就应该没问题。没有检查他们是否有不同的名字,只是名字的数量不同。 但它对我有用,你能详细说明它不适用的标准吗? 想象一下如果你有两个数组"A",true "B",true "C",true and "A",true "B",true "D",true。即使数组 1 有 C 并且数组 2 有 D 也没有检查可以捕捉到它。如果这种情况永远不会发生,那么您的代码就可以,如果可以,您的代码就不行。【参考方案4】:

首先,实现MyData.equals(Object o)MyData.hashCode() 方法。 实现 equals 方法后,您可以按如下方式遍历列表:

if(ListA == null && ListB == null)
    return false;
if(ListA == null && ListB != null)
    return true;
if(ListA != null && ListB == null)
    return true;
int max = ListA.size() > ListB.size() ? ListA.size() : ListB.size();
for(int i = 0; i < max; i++) 
    myData1 = ListA.get(i);
    myData2 = ListB.get(i);
    if(!myData1.equals(myData2)) 
        return true;
    

return false;

【讨论】:

始终实现equals() hashCode() -- 只实现其中一个可能会丢失集合中的元素或完全破坏集合。【参考方案5】:

我在List Compare 找到了一个非常基本的列表比较示例 此示例首先验证大小,然后检查一个列表的特定元素在另一个列表中的可用性。

【讨论】:

【参考方案6】:

覆盖类中的equals 方法并使用Collection#equals() 方法检查是否相等。

【讨论】:

始终实现equals() hashCode() -- 只实现其中一个可能会丢失集合中的元素或完全破坏集合。【参考方案7】:

您可以使用 CollectionUtils.subtract 从另一个列表中减去一个列表,如果结果是一个空集合,则意味着两个列表相同。另一种方法是使用 CollectionUtils.isSubCollection 或 CollectionUtils.isProperSubCollection。

在任何情况下,您都应该为您的对象实现 equals 和 hashCode 方法。

【讨论】:

【参考方案8】:

使用java 8 removeIf比较相似的项目

public int getSimilarItems()
    List<String> one = Arrays.asList("milan", "dingo", "elpha", "hafil", "meat", "iga", "neeta.peeta");
    List<String> two = new ArrayList<>(Arrays.asList("hafil", "iga", "binga", "mike", "dingo")); //Cannot remove directly from array backed collection
    int initial = two.size();

    two.removeIf(one::contains);
    return initial - two.size();

【讨论】:

【参考方案9】:

这可以通过 Java8 使用 forEach 和 removeIf 方法轻松完成。

取两个列表。从 listA 迭代并比较 listB

中的元素

removeIf 方法中写入任何条件。

希望这会有所帮助

listToCompareFrom.forEach(entity -> listToRemoveFrom.removeIf(x -> x.contains(entity)));

【讨论】:

【参考方案10】:

逻辑应该是这样的:

    第一步:对于MyData类实现Comparable接口,根据每个对象的要求重写compareTo方法。

    第二步:列表比较时(检查空值后), 2.1 检查两个列表的大小,如果相等返回true,否则返回false,继续对象迭代 2.2 如果步骤 2.1 返回 true,则遍历两个列表中的元素并调用类似的东西,

    listA.get(i).compareTo(listB.get(i))

这将按照步骤 1 中提到的代码。

【讨论】:

【参考方案11】:

看看这是否有效。

import java.util.ArrayList;
import java.util.List;


public class ArrayListComparison 

    public static void main(String[] args) 
        List<MyData> list1 = new ArrayList<MyData>();
        list1.add(new MyData("Ram", true));
        list1.add(new MyData("Hariom", true));
        list1.add(new MyData("Shiv", true));
//      list1.add(new MyData("Shiv", false));
        List<MyData> list2 = new ArrayList<MyData>();
        list2.add(new MyData("Ram", true));
        list2.add(new MyData("Hariom", true));
        list2.add(new MyData("Shiv", true));

        System.out.println("Lists are equal:" + listEquals(list1, list2));
    

    private static boolean listEquals(List<MyData> list1, List<MyData> list2) 
        if(list1.size() != list2.size())
            return true;
        for (MyData myData : list1) 
            if(!list2.contains(myData))
                return true;
        
        return false;
    


class MyData
    String name;
    boolean check;


    public MyData(String name, boolean check) 
        super();
        this.name = name;
        this.check = check;
    
    @Override
    public int hashCode() 
        final int prime = 31;
        int result = 1;
        result = prime * result + (check ? 1231 : 1237);
        result = prime * result + ((name == null) ? 0 : name.hashCode());
        return result;
    
    @Override
    public boolean equals(Object obj) 
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        MyData other = (MyData) obj;
        if (check != other.check)
            return false;
        if (name == null) 
            if (other.name != null)
                return false;
         else if (!name.equals(other.name))
            return false;
        return true;
    
 

【讨论】:

【参考方案12】:

从那时起已经过去了大约 5 年,幸运的是我们现在有了 Kotlin。 现在比较两个列表看起来很简单:

fun areListsEqual(list1 : List<Any>, list2 : List<Any>) : Boolean 
        return list1 == list2

或者完全忽略它并使用相等运算符。

【讨论】:

【参考方案13】:

我知道这是个老问题,但以防万一有人需要。我在我的应用程序中使用它并且效果很好。我用它来检查购物车是否已更改。

private boolean validateOrderProducts(Cart cart) 
    boolean doesProductsChanged = false;
    if (originalProductsList.size() == cart.getCartItemsList().size()) 
        for (Product originalProduct : originalProductsList) 
            if (!doesProductsChanged) 
                for (Product cartProduct : cart.getCartProducts()) 
                    if (originalProduct.getId() == cartProduct.getId()) 
                        if (originalProduct.getPivot().getProductCount() != cartProduct.getCount()) 
                            doesProductsChanged = true;
                            // cart has been changed -> break from inner loop
                            break;
                        
                     else 
                        doesProductsChanged = false;
                    
                
             else 
                // cart is already changed -> break from first loop
                break;
            
        
     else 
        // some products has been added or removed (simplest case of Change)
        return true;
    
    return doesProductsChanged;

【讨论】:

【参考方案14】:
String myData1 = list1.toString();
String myData2 = list2.toString()

return myData1.equals(myData2);

where :
list1 - List<MyData>
list2 - List<MyData>

比较字符串对我有用。另请注意,我在 MyData 类中重写了 toString() 方法。

【讨论】:

【参考方案15】:

如果其中一些是 HashSet 集合,我认为您可以对这两个列表进行排序并转换为 List。

java.utils.Collections 包让您可以做到。

List<Category> categoriesList = new ArrayList<>();
Set<Category> setList = new HashSet<>();
Collections.sort(categoriesList);
List<Category> fileCategories = new ArrayList<>(setList);
Collections.sort(fileCategories);

if(categoriesList.size() == fileCategories.size() && categoriesList.containsAll(fileCategories)) 
    //Do something

【讨论】:

以上是关于Java比较两个List的对象值?的主要内容,如果未能解决你的问题,请参考以下文章

如何判断两个对象的值是不是相等java

java反射反射实现判断发生了修改操作,判断两个对象是否发生属性值的变更,判断两个List集合内对象的属性值是否发生变更

Java中常见的集合类比较

java里的Collections类中的静态方法sort()是怎么用比较器比较两个对象?

如何比较两个对象数组以删除重复项?

浅谈Java对象的equals方法