使用Comparator而不是equals()比较两个Java集合 [英] Compare two Java Collections using Comparator instead of equals()

查看:162
本文介绍了使用Comparator而不是equals()比较两个Java集合的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

问题陈述



我有两个相同类型对象的集合,我想比较。在这种情况下,我想基于一个属性来比较它们,这些属性不会影响对象的 equals()。在我的例子中,我使用名称的排名集合为例:

  public class Name {
private String name ;
private int weightedRank;

// getters& setters

@Override
public boolean equals(Object obj){
return this.name.equals(obj.name); // Naive实现只是为了显示
// equals是基于name字段。
}
}



我想比较两个集合来断言,对于每个集合中的位置 i ,每个名称在该位置的 weightedRank 是相同的值。我做了一些Googling,但没有找到一个合适的方法在Commons Collections或任何其他API,所以我想出了以下:

  public< T> boolean comparatorEquals(Collection< T> col1,Collection< T> col2,
Comparator< T> c)
{
if(col1 == null)
return col2 == null ;
if(col2 == null)
return false;

if(col1.size()!= col2.size())
return false;

迭代器< T> i1 = col1.iterator(),i2 = col2.iterator();

while(i1.hasNext()&& i2.hasNext()){
if(c.compare(i1.next(),i2.next())!= 0){
return false;
}
}

return true;
}



问题



有另一种方法吗?



相关



我也发现了这个问题的SO,这是相似的,虽然在那

编辑



与此非常相似的内容将发布到 Apache Commons Collections 在不久的将来(在写这篇文章的时候)。请参见 https://issues.apache.org/jira/browse/COLLECTIONS-446

解决方案

我不知道这种方式实际上是更好,但它是另一种方式...



获取原始的两个集合,并为每个基础对象创建包含适配器的新集合。适配器应该具有 .equals() .hashCode() Name.calculateWeightedRank()。



* Edit *



使用Eclipse的标准hashCode / equals生成 Adapter 。您的代码将在每个基本集合上调用adaptCollection,然后调用List.equals()这两个结果。

  {

public List< Adapter> adaptCollection(List< Name> names){
List< Adapter> adapters = new ArrayList< Adapter>(names.size());

for(Name name:names){
adapters.add(new Adapter(name));
}

返回适配器;
}


private final int name;

public Adapter(Name name){
this.name = name.getWeightedResult();
}

@Override
public int hashCode(){
final int prime = 31;
int result = 1;
result = prime * result + name;
return result;
}

@Override
public boolean equals(Object obj){
if(this == obj)
return true;
if(obj == null)
return false;
if(getClass()!= obj.getClass())
return false;
Adapter other =(Adapter)obj;
if(name!= other.name)
return false;
return true;
}

}


Problem Statement

I have two Collections of the same type of object that I want to compare. In this case, I want to compare them based on an attribute that does not factor into equals() for the Objects. In my example, I'm using ranked collections of Names for instance:

public class Name {
    private String name;
    private int weightedRank;

    //getters & setters

    @Override
    public boolean equals(Object obj) {
        return this.name.equals(obj.name); //Naive implementation just to show
                                           //equals is based on the name field.
    }
}

I want to compare the two Collections to assert that, for position i in each Collection, the weightedRank of each Name at that position is the same value. I did some Googling but didn't find a suitable method in Commons Collections or any other API so I came up with the following:

public <T> boolean comparatorEquals(Collection<T> col1, Collection<T> col2,
        Comparator<T> c)
{
    if (col1 == null)
        return col2 == null;
    if (col2 == null) 
        return false;

    if (col1.size() != col2.size())
        return false;

    Iterator<T> i1 = col1.iterator(), i2 = col2.iterator();

    while(i1.hasNext() && i2.hasNext()) {
        if (c.compare(i1.next(), i2.next()) != 0) {
            return false;
        }
    }

    return true;
}

Question

Is there another way to do this? Did I miss an obvious method from Commons Collections?

Related

I also spotted this question on SO which is similar though in that case I'm thinking overriding equals() makes a little more sense.

Edit

Something very similar to this will be going into a release of Apache Commons Collections in the near future (at the time of this writing). See https://issues.apache.org/jira/browse/COLLECTIONS-446.

解决方案

I'm not sure this way is actually better, but it is "another way"...

Take your original two collections, and create new ones containing an Adapter for each base object. The Adapter should have .equals() and .hashCode() implemented as being based on Name.calculateWeightedRank(). Then you can use normal Collection equality to compare the collections of Adapters.

* Edit *

Using Eclipse's standard hashCode/equals generation for the Adapter. Your code would just call adaptCollection on each of your base collections, then List.equals() the two results.

public class Adapter {

    public List<Adapter> adaptCollection(List<Name> names) {
        List<Adapter> adapters = new ArrayList<Adapter>(names.size());

        for (Name name : names) {
            adapters.add(new Adapter(name));
        }

        return adapters;
    }


    private final int name;

    public Adapter(Name name) {
        this.name = name.getWeightedResult();
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + name;
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Adapter other = (Adapter) obj;
        if (name != other.name)
            return false;
        return true;
    }

}

这篇关于使用Comparator而不是equals()比较两个Java集合的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆