【问题标题】:How to remove duplicates from ArrayList of type Object? [duplicate]如何从 Object 类型的 ArrayList 中删除重复项? [复制]
【发布时间】:2014-06-18 12:35:30
【问题描述】:

我想从 Alerts 类型的 ArrayList 中删除重复项,其中 Alerts 是一个类。

班级提醒 -

public class Alerts implements Parcelable {
    String date = null;
    String alertType = null;
    String discription = null;

    public Alerts() {

    }

    public Alerts(String date, String alertType, String discription) {
        super();
        this.date = date;
        this.alertType = alertType;
        this.discription = discription;
    }
}

这是我添加元素的方式 -

ArrayList<Alerts> alert = new ArrayList<Alerts>();
Alerts obAlerts = new Alerts();

obAlerts = new Alerts();
obAlerts.date = Date1.toString();
obAlerts.alertType = "Alert Type 1";
obAlerts.discription = "Some Text";
alert.add(obAlerts);

obAlerts = new Alerts();
obAlerts.date = Date2.toString();
obAlerts.alertType = "Alert Type 1";
obAlerts.discription = "Some Text";
alert.add(obAlerts);

我想从中删除的内容-

我想要所有具有唯一 obAlerts.dateobAlerts.alertType 的警报。换句话说,删除重复的obAlerts.dateobAlerts.alertType 警报。

我试过了 -

Alerts temp1, temp2;
String macTemp1, macTemp2, macDate1, macDate2;

for(int i=0;i<alert.size();i++)
 {    
    temp1 = alert.get(i);  
    macTemp1=temp1.alertType.trim(); 
    macDate1 = temp1.date.trim();

    for(int j=i+1;j<alert.size();j++)
    {

         temp2 = alert.get(j);  
        macTemp2=temp2.alertType.trim();  
        macDate2 = temp2.date.trim();

        if (macTemp2.equals(macTemp1) && macDate1.equals(macDate2))  
        {   
           alert.remove(temp2);           
        } 

    }
 }

我也试过-

HashSet<Alerts> hs = new HashSet<Alerts>();
hs.addAll(obAlerts);
obAlerts.clear();
obAlerts.addAll(hs);

【问题讨论】:

  • 您希望每个对象有一个不同的date一个不同的alertType。因此,如果 date OR alertType 对于两个对象相同,则必须删除该对象。
  • @G.T.是的。如何删除此类重复项?
  • 和你一样。只需在最后一个if 中将&amp;&amp; 替换为||

标签: android arraylist hashset linkedhashset


【解决方案1】:

您需要通过重写一对方法来指定类如何决定相等性:

public class Alert {

    String date;
    String alertType;

    @Override
    public boolean equals(Object o) {
        if (this == 0) {
            return true;
        }
        if ((o == null) || (!(o instanceof Alert)))
            return false;
        }
        Alert alert = (Alert) o;
        return this.date.equals(alert.date)
                && this.alertType.equals(alert.alertType);
    }

    @Override
    public int hashCode() {
        int dateHash;
        int typeHash;
        if (date == null) {
            dateHash = super.hashCode();
        } else {
            dateHash = this.date.hashCode();
        }
        if (alertType == null) {
            typeHash = super.hashCode();
        } else {
            typeHash = this.alertType.hashCode();
        }
        return dateHash + typeHash;
    }
}

然后,您可以循环遍历您的 ArrayList 并添加元素(如果它们不存在),因为 Collections.contains() 使用这些方法。

public List<Alert> getUniqueList(List<Alert> alertList) {
    List<Alert> uniqueAlerts = new ArrayList<Alert>();
    for (Alert alert : alertList) {
        if (!uniqueAlerts.contains(alert)) {
            uniqueAlerts.add(alert);
        }
    }
    return uniqueAlerts;
}

不过,说了这么多之后,您可能想重新审视您的设计,以使用不允许重复元素的 Set 或其家族之一。取决于你的项目。 Here's a comparison of Collections types

【讨论】:

  • 我想要datealertType 相等。那么我可以在equals 方法中使用return this.date.equals(alert.date) &amp;&amp; this.alertType.equals(alert.alertType); 吗?
  • 您可以使用任何您喜欢的条件,但请确保在计算hashCode 时包含alertType 字段;这两种方法必须匹配,这样如果a.equals(b) 那么a.hashCode() equals b.hashCode()
  • 只需使用 List depdupeCustomers = new ArrayList( new LinkedHashSet(alert)); 而不是那些用于唯一列表的循环 Statemts
  • 给定的示例代码可以改进。永远不要盲目地做演员并依靠尝试接球。将异常用于控制流是一种反模式,因为创建异常的成本非常高。另外,equals 方法不符合 javadoc 规范(比较我的答案中链接的线程),因为当您将 null 传递给它时,它会抛出 NullPointerException
  • 现在可能与我的代码审查员的声音说话,但是您的 hashCode 方法的最新版本不一致,因为只要至少一个主键字段是 null,它就会产生不同的结果.例如。两个实例,其中日期为 null 和 alertType 在两个实例中都相等。您的实现将为那些语义相同的实例提供不同的哈希值,因为在null 的情况下您会回退到super.hashCode()。但是,让我们将选择正确的后备值作为练习留给 OP,不是吗? :)
【解决方案2】:

您可以使用Set&lt;&gt;。从本质上讲,集合不包括重复项。你只需要确保你有一个正确的hashCode()equals() 方法。

【讨论】:

  • 查看更新。我使用了 HashSet 但重复项仍然存在。你能说明一下吗?
【解决方案3】:

在您的Alerts 类中,覆盖hashCodeequals 方法以依赖于您希望作为主键的字段的值。之后,您可以在迭代ArrayList 时使用HashSet 来存储已经看到的实例。当您找到不在HashSet 中的实例时,将其添加到HashSet,否则将其从ArrayList 中删除。为了让您的生活更轻松,您可以完全切换到 HashSet 并完成重复项本身。

注意覆盖 hashCodeequalssome constraints apply

This thread 有一些关于如何编写好的hashCode 函数的有用指导。一个重要的教训是,简单地将所有相关字段的哈希码相加是不够的,因为在字段之间交换值将导致相同的哈希码,这可能是不可取的(比较交换名字和姓氏)。相反,通常在添加下一个原子哈希之前完成某种移位操作,例如。与素数相乘。

【讨论】:

  • 查看更新。我尝试了 HashSet 没有成功。你能说明一下吗?
  • @VedPrakash 在Alerts 类中覆盖hashCodeequals强制。如果密钥对象中没有适当的哈希码操作,HashSet 将毫无价值,因为它将基于“它是重复的吗?”的决定。在本机哈希码上,无论字段的值如何,对于所有不同的对象都是不同的。
  • @VedPrakash 更新了我的答案以添加有关如何编写好的 hashCode 函数的信息。
【解决方案4】:

首先将您的数据存储在数组中,然后将其拆分为一个一个字符串,直到该数据的长度执行arry并通过if条件与acyual数据进行比较并重新调整它,

HashSet<String> hs = new HashSet<String>(); 

for(int i=0;i<alert.size();i++)
{
    hs.add(alert.get(i).date + ","+ alert.get(i).alertType;
}

alert.clear();

String alertAll[] = null;
for (String s : hs) {   

    alertAll = s.split(",");
    obAlerts = new Alerts();
    obAlerts.date = alertAll[0];
    obAlerts.alertType = alertAll[1];
    alert.add(obAlerts);
}

【讨论】:

  • 你能举个例子来说明一下吗?
  • @VedPrakash 不要自己动手,除非你正在学习数据结构。
  • 谢谢,你是对的!
猜你喜欢
  • 2013-09-04
  • 1970-01-01
  • 2018-05-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-05-23
  • 2015-12-12
  • 1970-01-01
相关资源
最近更新 更多