通过比较,而不是比较平等的两个Java集合()(Compare two Java Collectio

2019-08-17 04:25发布

问题陈述

我有相同类型的对象,我想比较的两个集合。 在这种情况下,我想根据不计算入一个属性对它们进行比较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 implementation just to show
                                           //equals is based on the name field.
    }
}

我想这两个类别比较断言,对于位置i在每个系列中, weightedRank在那个位置上的每个名称是相同的值。 我做了一些谷歌搜索,但没有找到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;

    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;
}

是否有另一种方式做到这一点? 我错过从Commons Collections中一个明显的方法是什么?

有关

我也发现这个问题上的SO这是类似,虽然在这种情况下,我想最主要equals()让人有点更有意义。

编辑

东西非常相似,这将是进入的一个版本的Apache Commons Collections中在不久的将来(在写这篇文章的时间)。 见https://issues.apache.org/jira/browse/COLLECTIONS-446 。

Answer 1:

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

把你原来的两个集合,然后创建一个包含每个基本对象的适配器新的。 适配器应有.equals().hashCode()为是基于实施Name.calculateWeightedRank() 然后你可以使用正常的收藏平等比较适配器的集合。

*编辑*

使用Eclipse标准的hashCode /等于一代的Adapter 。 您的代码只是调用adaptCollection在每个基地集合,然后List.equals()两个结果。

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;
    }

}


Answer 2:

您可以使用番石榴等价类,以分离的“比较”和“对等”的概念。 你仍然会写你的比较方法(据我所知番石榴没有它)接受一个等价的子类,而不是比较,但至少你的代码会少些混乱,你可以基于任何等价标准比较你的收藏。

使用equivance包裹对象的集合(见在等值包装方法 )是类似于sharakan提出了基于适配器的解决方案,但等价实施将从适配器实现脱钩,让您轻松使用多个等价标准。



Answer 3:

您可以使用新的isEqualCollection加入方法CollectionUtils因为版本4.此方法使用提供的外部comparsion机制Equator接口实现。 请检查此的javadoc: CollectionUtils.isEqualCollection(...)和赤道 。



Answer 4:

编辑 :删除旧的答案。

你有被称为创建一个接口的另一种选择Weighted可能看起来像这样的:

public interface Weighted {
    int getWeightedRank();
}

然后让你的Name的类实现此接口。 然后你可以改变你的方法是这样的:

 public <T extends Weighted> boolean weightedEquals(Collection<T> col1, Collection<T> col2)
{
    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 (i1.next().getWeightedRank() != i2.next().getWeightedRank()) {
          return false;
      }
  }

  return true;
}

然后,当你发现需要额外的类进行加权比较,你可以把它们放在你的收藏中,他们可以互相以及进行比较。 只是一个想法。



文章来源: Compare two Java Collections using Comparator instead of equals()