2014-12-24 73 views
3

我想从我的数组中删除重复的对象。删除自定义对象的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用x总是嘱咐。

谢谢大家。

+0

通常情况下,'X == X + 1'是不正确的。你可能的意思是'x == x1',并将它与事实混淆起来,在你的列表中,具有相同'x'值的条目被连续存储。 – didierc

+0

对不起,谢谢 – user2335528

+0

现在,如果你在x和y上正确地分类你的物品,问题就变得微不足道了。 – didierc

回答

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中自动生成它们。

0

确保在自定义对象(MyObject)中覆盖equals()方法。

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

+0

我不知道如何使用它。我已经实现了平等,但没有成功...... – user2335528

0

使用Set,而不是List ...

您必须覆盖equals()hashCode()。最IDE可​​以为你生成!

“转换”列表的设置,你可以简单地使用:

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

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

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

好吧我得到它,我需要实现equals和hashcode,但接下来我该怎么做呢? – user2335528

+0

我已经更新了我的答案。只是为了澄清:你必须为你的MyObject类重写'equals()'和'hashCode()' – sockeqwe

0

您需要订购两个xyx第一您的收藏(想想作为XÿX形成假设数目在小数点左边,在右边:按照增长顺序对数字进行排序,如果整数部分相等,则按小数部分排序)。 现在,使用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)及时(不计算排序,如果我正确理解你的问题,这应该发生)。


另外,整个过滤可以通过在你的集合,其中折叠这里应用实现仅仅是保持最高y对于相同x(如你在你的问题恰恰说明它)。由于您的收藏已按x排序,这意味着它自然按x的值进行分区,因此您可以通过为另一个阵列中的每个分区累积正确的x来构建新集合。对于数组中的每个元素,你在你的新数组最后插入的条目进行比较,如果x都是一样的,你用最高y对象替换它。如果x不同,则将其添加到新阵列。

这种方法的好处是,你并不需要更改排序算法,但在另一方面,你需要一个新的阵列。这个算法因此应该在O(n)空间和时间。

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

伪代码:

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

注意,在不断的空间内工作时,这可能是因为ArrayList内部工作(尽管它应该是比其他以往更好的方式略高于分配算法效率较低,容器类型)。

0

最优化的解决方案是,如果你可以使用一个Set。但是,有两个Set实现在Java中:HashSetTreeSetHashSet要求您声明equalshashCode方法,而TreeSet要求您的班级使用compareTo方法实施Comparable或提供Comparator。这两种解决方案都不会起作用,因为当x相等时,您希望保持较高的y。如果您根据x,yx进行排序/计算,您将会有重复的x,并且如果根据x排序/计算相等性,则只会输入第一个x,这不是您想要的。

因此,我们需要做的是:

  1. 排序X上升,Y降
  2. 转换为Set,可以保留原来的顺序,但基地的平等只有在x
  3. 转换回列表(如有必要)

XAscYdesc比较方法(不占空值):

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

XAsc比较方法(不占空值):

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

(使用番石榴库;它是单行这样)非常有用:

Collections.sort(list, new XAscYdesc()); 
Lists.newArrayList(ImmutableSortedSet.copyOf(new XAsc(), list)); 
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; 
    } 

} 
+0

当回答问题时,最好更详细地解释一下,以便其他用户更容易理解现场。 – Tristan