查看ArrayList是否包含Java中的对象的最有效方法
我有一个Java对象的ArrayList。对象有四个字段,其中两个字段用于将对象视为与另一个对象相等的字段。考虑到这两个字段,我正在寻找最有效的方法来查看数组是否包含该对象 问题是这些类是基于XSD对象生成的,所以我不能修改类本身来覆盖查看ArrayList是否包含Java中的对象的最有效方法,java,algorithm,optimization,search,arraylist,Java,Algorithm,Optimization,Search,Arraylist,我有一个Java对象的ArrayList。对象有四个字段,其中两个字段用于将对象视为与另一个对象相等的字段。考虑到这两个字段,我正在寻找最有效的方法来查看数组是否包含该对象 问题是这些类是基于XSD对象生成的,所以我不能修改类本身来覆盖.equals 有没有更好的方法,不只是循环并手动比较每个对象的两个字段,然后在找到时中断?这看起来很混乱,在寻找更好的方法 编辑:ArrayList来自一个SOAP响应,该响应被解组为对象。如果列表是,您可以使用。如果没有,那就没有更好的办法了 如果你经常这样做
.equals
有没有更好的方法,不只是循环并手动比较每个对象的两个字段,然后在找到时中断?这看起来很混乱,在寻找更好的方法
编辑:ArrayList来自一个SOAP响应,该响应被解组为对象。如果列表是,您可以使用。如果没有,那就没有更好的办法了
如果你经常这样做,那么第一次对列表进行排序几乎肯定是值得的。由于您无法修改类,因此必须使用a来进行排序和搜索。即使equals方法比较这两个字段,从逻辑上讲,它与您手动执行的代码相同。好的,它可能是“混乱的”,但它仍然是正确的答案鉴于您的限制,您必须使用暴力搜索(或者如果搜索将重复,则创建索引)。你能详细说明一下
ArrayList
是如何生成的吗?也许还有一些回旋余地
如果你所寻找的是更漂亮的代码,考虑使用Apache CuMon集合类,特别是对于现成的句法糖:
ArrayList haystack = // ...
final Object needleField1 = // ...
final Object needleField2 = // ...
Object found = CollectionUtils.find(haystack, new Predicate() {
public boolean evaluate(Object input) {
return needleField1.equals(input.field1) &&
needleField2.equals(input.field2);
}
});
从性能角度来看,根据字段值作为键来构建这些对象的HashMap可能是值得的,例如,一次填充映射并非常高效地查找对象如果需要在同一列表中多次搜索,构建索引可能会有好处 迭代一次,然后构建一个HashMap,将要查找的equals值作为键,将适当的节点作为值。如果需要all而不是给定equals值的任何一个,那么让映射具有值类型list,并在初始迭代中构建整个列表
请注意,在执行此操作之前,您应该进行测量,因为在找到预期的节点之前,构建索引的开销可能会超过仅进行遍历的开销。这取决于您需要的效率。如果可以实现Equals方法,只需在列表上迭代查找满足特定条件的元素就是O(n),但ArrayList.Contains也是O(n)。如果您不是在循环或内部循环中执行此操作,那么这种方法可能很好 如果您真的需要不惜一切代价提高查找速度,则需要做两件事:
*
()实现hashCode()的最佳方法是对用于equals实现的相同字段的hashCode进行异或(^运算符)(但为了减少异或产生0的可能性)您可以使用带有Java内置方法的比较器进行排序和二进制搜索。假设您有这样一个类,其中a和b是要用于排序的字段:
class Thing { String a, b, c, d; }
您可以定义比较器:
Comparator<Thing> comparator = new Comparator<Thing>() {
public int compare(Thing o1, Thing o2) {
if (o1.a.equals(o2.a)) {
return o1.b.compareTo(o2.b);
}
return o1.a.compareTo(o2.a);
}
};
最后进行二进制搜索:
int i = Collections.binarySearch(list, thingToFind, comparator);
有三个基本选项: 1) 如果检索性能是最重要的,并且这样做是可行的,那么使用一种只构建一次的哈希表形式(并在列表更改时进行更改) 2) 如果可以方便地对列表进行排序,或者可以对其进行排序,并且O(logn)检索就足够了,请进行排序和搜索 3) 如果O(n)检索足够快,或者如果操作/维护数据结构或备用数据结构是不切实际的,则迭代列表 在编写比列表上的简单迭代更复杂的代码之前,有必要考虑一些问题
- 为什么需要一些不同的东西?(时间)性能?优雅?可维护性?重新使用所有这些都是好的理由,不管是分开的还是一起的,但它们都会影响解决方案
- 您对所讨论的数据结构有多大的控制权?你能影响它的建造方式吗?以后处理
- 数据结构(和底层对象)的生命周期是什么?它是一次建成,从未改变,还是高度动态?你的代码能监控(甚至改变)它的生命周期吗
- 是否还有其他重要的限制,例如内存占用?关于重复的信息重要吗?等等
List list = new ArrayList();
fillFromSoap( list );
致:
实施过程将是非常艰难的
List list = new ArrayList();
fillFromSoap( list );
List list = new MyCustomSpecialList();
fillFromSoap( list );
class MyCustomSpecialList extends AbstractList {
private Map<Integer, YourObject> internalMap;
public boolean add( YourObject o ) {
internalMap.put( o.getThatFieldYouKnow(), o );
}
public boolean contains( YourObject o ) {
return internalMap.containsKey( o.getThatFieldYouKnow() );
}
public class Widget {
private String name;
private String desc;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
}
public abstract class EqualsHashcodeEnforcer<T> {
protected T wrapped;
public T getWrappedObject() {
return wrapped;
}
@Override
public boolean equals(Object obj) {
return equalsDelegate(obj);
}
@Override
public int hashCode() {
return hashCodeDelegate();
}
protected abstract boolean equalsDelegate(Object obj);
protected abstract int hashCodeDelegate();
}
public class WrappedWidget extends EqualsHashcodeEnforcer<Widget> {
@Override
protected boolean equalsDelegate(Object obj) {
if (obj == null) {
return false;
}
if (obj == getWrappedObject()) {
return true;
}
if (obj.getClass() != getWrappedObject().getClass()) {
return false;
}
Widget rhs = (Widget) obj;
return new EqualsBuilder().append(getWrappedObject().getName(),
rhs.getName()).append(getWrappedObject().getDesc(),
rhs.getDesc()).isEquals();
}
@Override
protected int hashCodeDelegate() {
return new HashCodeBuilder(121, 991).append(
getWrappedObject().getName()).append(
getWrappedObject().getDesc()).toHashCode();
}
}
Foo foo = ...
Detect<Foo> query = Detect.from(list);
for (Detect<Foo> each: query)
each.yield = each.element.a == foo.a && each.element.b == foo.b;
return query.result();