删除Custom对象的ArrayList中的重复项

时间:2014-12-24 10:56:04

标签: java android algorithm sorting arraylist

我正在尝试从数组中删除重复的对象。

我的自定义由两个双重组成:x和y。

我想要做的是删除重复((x&& y)==(x1&& y1))如果x == x1我想保留具有更高y的对象。

ArrayList<MyObject> list = [x(0),y(0)], [x(0),y(0)], [x(0.5),y(0.5], [x(0.5),y(0.6)], [x(1),y(1)]; 
ArrayList<MyObject> results = [x(0),y(0)], [x(0.5),y(0.6)], [x(1),y(1)]; 

我尝试实现equals方法,但我不知道如何使用它:

public boolean equals(Object obj) {
    if (obj == null || !(obj instanceof MyObject)) {
        return false;
    }
    return (this.x == ((MyObject)obj).x);
}
始终使用Collections.sort by x对

列表进行排序。

谢谢大家。

6 个答案:

答案 0 :(得分:6)

鉴于此MyObject

class MyObject {
    private final double x;
    private final double y;

    public MyObject(double x, double y) {
        this.x = x;
        this.y = y;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        MyObject myObject = (MyObject) o;

        if (Double.compare(myObject.x, x) != 0) return false;
        if (Double.compare(myObject.y, y) != 0) return false;

        return true;
    }

    @Override
    public int hashCode() {
        int result;
        long temp;
        temp = Double.doubleToLongBits(x);
        result = (int) (temp ^ (temp >>> 32));
        temp = Double.doubleToLongBits(y);
        result = 31 * result + (int) (temp ^ (temp >>> 32));
        return result;
    }
}

您可以实现一个unique方法,该方法仅返回包含唯一元素的列表:

private List<MyObject> unique(List<MyObject> list) {
    List<MyObject> uniqueList = new ArrayList<>();
    Set<MyObject> uniqueSet = new HashSet<>();
    for (MyObject obj : list) {
        if (uniqueSet.add(obj)) {
            uniqueList.add(obj);
        }
    }
    return uniqueList;
}

对其进行单元测试以验证其有效:

@Test
public void removeDups() {
    List<MyObject> list = Arrays.asList(new MyObject(0, 0), new MyObject(0, 0), new MyObject(0.5, 0.5), new MyObject(0.5, 0.6), new MyObject(1, 1));
    List<MyObject> results = Arrays.asList(new MyObject(0, 0), new MyObject(0.5, 0.5), new MyObject(0.5, 0.6), new MyObject(1, 1));
    assertEquals(results, unique(list));
}

注意:要实现此equalshashCode这一点非常重要, 因为使用了哈希映射。但是,您应该始终在自定义类中执行此操作:提供适当的equalshashCode实现。顺便说一下,我没有写出equalshashCode方法。我让我的IDE(IntelliJ)从类的xy字段自动生成它们。

答案 1 :(得分:0)

请务必覆盖自定义对象(equals())中的MyObject方法。

然后将它们添加到Set。现在你有了独特的结果集。

答案 2 :(得分:0)

使用Set代替List ...

您必须覆盖equals()hashCode()。大多数IDE都可以为您生成!

要将List“转换”为Set,您只需使用它:

ArrayList<MyObject> list =  ...
Set<MyObject> mySet = new HashSet<MyObject>(list);

然后你有一个具有独特元素的集合。您可以像这样遍历集合:

for (MyObject o : mySet){
   o.getX();
}

答案 3 :(得分:0)

您需要首先在xy上使用x订购您的收藏集(将其视为 x y 在小数点左侧用 x 形成一个假设数字,在右侧用 y 形成一个假设数字:当你按生长顺序排序数字时,如果整数部分是相等,你按小数部分排序)。 现在,使用equal谓词,很难对值进行排序(您只能判断它们是否相等,而不是一个在另一个之前)。相反,您需要使用以下方法实现comparable接口:

public int compare(Object obj) {
  if (obj == null || !(obj instanceof MyObject)) {
    // raise an Exception
  }
  MyObject other = (MyObject)obj;
  if (x < other.x) return -1;
 if (this.x > other.x) return 1;
  if (this.y < other.y) return -1;
  if (this.y > other.y) return 1;
  return 0;
}

如果根据此比较对数组进行排序,则只需在数组中保留最后一个具有相同x的条目即可获得所需内容。这意味着您删除条目,除非其后继者具有不同的x

这个方法很有意思,你不想保留你的原始数据,但只保留结果:它将更新现有的数组,复杂的 O(n) in时间(不计算排序,如果我理解你的问题,无论如何都会发生。)


或者,可以通过在您的收藏中应用 fold 来实现整个过滤,其中折叠只是保持同一y的最高x(就像您一样)在你的问题中准确说明了)。由于您的集合已经在x上排序,这意味着它自然会在x的值上进行分区,因此您可以通过累积正确{{1}来构建新集合对于另一个数组中的每个分区。对于数组的每个元素,将其与新数组中最后插入的条目进行比较,如果x相同,则将其替换为具有最高x的对象。如果y不同,则将其添加到新数组中。

这种方法的优点是你不需要改变排序算法,但另一方面你需要一个新的数组。因此,该算法应该在 O(n)空间和时间中工作。

最后,该算法可以适用于原始阵列的原位更新。它稍微复杂一点,但可以避免额外的分配(对嵌入式系统至关重要)。

伪代码:

x

请注意,在常量空间中工作时,它的效率可能略低于分配算法,因为int idx = 0; while (idx + 1 < Objarray.size()){ MyObj oi = Objarray.get(idx), on = Objarray.get(idx+1); if (oi.x == on.x) { if (on.y < oi.y) Objarray.remove(idx++); else Objarray.remove(idx+1); } else idx++; } 在内部工作的方式(尽管它应该比使用其他常用的容器类型更好)。

答案 4 :(得分:0)

最佳解决方案是使用Set。但是,Java中有两个Set实现:HashSetTreeSetHashSet要求您声明equalshashCode方法,而TreeSet要求您的班级使用Comparable方法实施compareTo或提供{ {1}}。这两种解决方案都不适用于您的情况,因为您希望在Comparator相等时保持较高的y。如果您根据xx排序/计算相等性,则会有重复y,如果您根据x排序/计算相等性,则只会得到第一个x {1}}已输入,这不是您想要的。

因此,我们需要做的是:

  1. 按x升序,y降序排序
  2. 转换为保留原始订单的x,但仅在Set上基础相等
  3. 转换回列表(如有必要)
  4. XAscYdesc比较器方法(不考虑空值):

    x

    XAsc比较器方法(不考虑空值):

    public int compare(MyObject left, MyObject right) {
      int c = left.x - right.x;
      if(c != 0) {
        return c;
      }
      return right.y - left.y;
    }
    

    (使用Guava库;对于像这样的单行程序非常有用):

    public int compare(MyObject left, MyObject right) {
      return left.x - right.x;
    }
    

答案 5 :(得分:0)

/**
 * 
 */
package test1;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * @author raviteja
 *
 */
public class UinquecutomObjects {

    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Employee e1=new Employee();
        e1.setName("abc");
        e1.setNo(1);

        Employee e2=new Employee();
        e2.setName("def");
        e2.setNo(2);

        Employee e3=new Employee();
        e3.setName("abc");
        e3.setNo(1);

        List<Employee> empList=new ArrayList<Employee>();
        empList.add(e1);
        empList.add(e2);
        empList.add(e3);

        System.out.println("list size is "+empList.size());

        Set<Employee> set=new HashSet<Employee>(empList);

        System.out.println("set size is "+set.size());
        System.out.println("set elements are  "+set);



    }

}


class Employee{

    private String name;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getNo() {
        return no;
    }
    public void setNo(int no) {
        this.no = no;
    }
    private int no;
    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((name == null) ? 0 : name.hashCode());
        result = prime * result + no;
        return result;
    }
    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Employee other = (Employee) obj;
        if (name == null) {
            if (other.name != null)
                return false;
        } else if (!name.equals(other.name))
            return false;
        if (no != other.no)
            return false;
        return true;
    }

}