Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/visual-studio-2008/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
查看ArrayList是否包含Java中的对象的最有效方法_Java_Algorithm_Optimization_Search_Arraylist - Fatal编程技术网

查看ArrayList是否包含Java中的对象的最有效方法

查看ArrayList是否包含Java中的对象的最有效方法,java,algorithm,optimization,search,arraylist,Java,Algorithm,Optimization,Search,Arraylist,我有一个Java对象的ArrayList。对象有四个字段,其中两个字段用于将对象视为与另一个对象相等的字段。考虑到这两个字段,我正在寻找最有效的方法来查看数组是否包含该对象 问题是这些类是基于XSD对象生成的,所以我不能修改类本身来覆盖.equals 有没有更好的方法,不只是循环并手动比较每个对象的两个字段,然后在找到时中断?这看起来很混乱,在寻找更好的方法 编辑:ArrayList来自一个SOAP响应,该响应被解组为对象。如果列表是,您可以使用。如果没有,那就没有更好的办法了 如果你经常这样做

我有一个Java对象的ArrayList。对象有四个字段,其中两个字段用于将对象视为与另一个对象相等的字段。考虑到这两个字段,我正在寻找最有效的方法来查看数组是否包含该对象

问题是这些类是基于XSD对象生成的,所以我不能修改类本身来覆盖
.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)。如果您不是在循环或内部循环中执行此操作,那么这种方法可能很好

如果您真的需要不惜一切代价提高查找速度,则需要做两件事:

  • 围绕以下事实开展工作: 生成:编写一个适配器类 可以包装生成的类和 基于哪个实现 在这两个字段上(假设 是公共的)。也别忘了 实施(*)
  • 用该适配器包装每个对象,然后 把它放在哈希集中。 有恒量 访问时间,即O(1)而不是O(n)
  • 当然,构建此哈希集仍然需要O(n)成本。如果构建HashSet的成本与您需要执行的所有contains()检查的总成本相比可以忽略不计,那么您将获得任何收益。试图构建一个没有重复项的列表就是这种情况


    *
    ()实现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)检索足够快,或者如果操作/维护数据结构或备用数据结构是不切实际的,则迭代列表

    在编写比列表上的简单迭代更复杂的代码之前,有必要考虑一些问题

    • 为什么需要一些不同的东西?(时间)性能?优雅?可维护性?重新使用所有这些都是好的理由,不管是分开的还是一起的,但它们都会影响解决方案

    • 您对所讨论的数据结构有多大的控制权?你能影响它的建造方式吗?以后处理

    • 数据结构(和底层对象)的生命周期是什么?它是一次建成,从未改变,还是高度动态?你的代码能监控(甚至改变)它的生命周期吗

    • 是否还有其他重要的限制,例如内存占用?关于重复的信息重要吗?等等

    有没有更好的方法,不只是循环并手动比较每个对象的两个字段,然后在找到时中断?这看起来很混乱,在寻找更好的方法

    如果您关心的是可维护性,那么您可以做建议的事情(我也会这么做),尽管这可能不是“最有效的”(因为您必须先对数组排序,然后执行二进制搜索),但肯定是最干净、更好的选择

    如果您真的关心效率,那么可以创建一个自定义列表实现,该实现使用对象中的字段作为哈希,并使用哈希映射作为存储。但这可能太过分了

    然后,您必须更改将数据从ArrayList填充到CustomList的位置

    比如:

     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();