我正在尝试从数组中删除重复的对象。
我的自定义由两个双重组成: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对列表进行排序。
谢谢大家。
答案 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));
}
注意:要实现此equals
和hashCode
这一点非常重要,
因为使用了哈希映射。但是,您应该始终在自定义类中执行此操作:提供适当的equals
和hashCode
实现。顺便说一下,我没有写出equals
和hashCode
方法。我让我的IDE(IntelliJ)从类的x
和y
字段自动生成它们。
答案 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)
您需要首先在x
和y
上使用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
实现:HashSet
和TreeSet
。 HashSet
要求您声明equals
和hashCode
方法,而TreeSet
要求您的班级使用Comparable
方法实施compareTo
或提供{ {1}}。这两种解决方案都不适用于您的情况,因为您希望在Comparator
相等时保持较高的y
。如果您根据x
,x
排序/计算相等性,则会有重复y
,如果您根据x
排序/计算相等性,则只会得到第一个x
{1}}已输入,这不是您想要的。
因此,我们需要做的是:
x
,但仅在Set
上基础相等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;
}
}