Most efficient way to see if an ArrayList contains an object in Java

后端 未结 12 1088
孤城傲影
孤城傲影 2020-11-30 18:25

I have an ArrayList of objects in Java. The objects have four fields, two of which I\'d use to consider the object equal to another. I\'m looking for the most efficient wa

相关标签:
12条回答
  • 2020-11-30 19:05

    There are three basic options:

    1) If retrieval performance is paramount and it is practical to do so, use a form of hash table built once (and altered as/if the List changes).

    2) If the List is conveniently sorted or it is practical to sort it and O(log n) retrieval is sufficient, sort and search.

    3) If O(n) retrieval is fast enough or if it is impractical to manipulate/maintain the data structure or an alternate, iterate over the List.

    Before writing code more complex than a simple iteration over the List, it is worth thinking through some questions.

    • Why is something different needed? (Time) performance? Elegance? Maintainability? Reuse? All of these are okay reasons, apart or together, but they influence the solution.

    • How much control do you have over the data structure in question? Can you influence how it is built? Managed later?

    • What is the life cycle of the data structure (and underlying objects)? Is it built up all at once and never changed, or highly dynamic? Can your code monitor (or even alter) its life cycle?

    • Are there other important constraints, such as memory footprint? Does information about duplicates matter? Etc.

    0 讨论(0)
  • 2020-11-30 19:15

    If you are a user of my ForEach DSL, it can be done with a Detect query.

    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();
    
    0 讨论(0)
  • 2020-11-30 19:15

    I would say the simplest solution would be to wrap the object and delegate the contains call to a collection of the wrapped class. This is similar to the comparator but doesn't force you to sort the resulting collection, you can simply use ArrayList.contains().

    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();
            }
    
        }
    
    0 讨论(0)
  • 2020-11-30 19:21

    If the list is sorted, you can use a binary search. If not, then there is no better way.

    If you're doing this a lot, it would almost certainly be worth your while to sort the list the first time. Since you can't modify the classes, you would have to use a Comparator to do the sorting and searching.

    0 讨论(0)
  • 2020-11-30 19:21

    Even if the equals method were comparing those two fields, then logically, it would be just the same code as you doing it manually. OK, it might be "messy", but it's still the correct answer

    0 讨论(0)
  • 2020-11-30 19:24

    If you need to search many time in the same list, it may pay off to build an index.

    Iterate once through, and build a HashMap with the equals value you are looking for as the key and the appropriate node as the value. If you need all instead of anyone of a given equals value, then let the map have a value type of list and build the whole list in the initial iteration.

    Please note that you should measure before doing this as the overhead of building the index may overshadow just traversing until the expected node is found.

    0 讨论(0)
提交回复
热议问题