【问题标题】:Java, searching within a list of objects?Java,在对象列表中搜索?
【发布时间】:2011-07-08 10:57:17
【问题描述】:

在以最快的速度实现这一目标的过程中,我有点迷失了方向。我有一大堆具有基本变量属性(带有 getter / setter)的对象,我需要在此列表中进行搜索以查找列表中与给定参数匹配的对象

我找到了如何进行常规列表搜索,但我需要,例如搜索对列表中的每个对象执行 getName() 调用的结果的值,并获取结果与我的匹配的对象输入。

如下所示,第三个参数是方法调用的结果,第二个是我要查找的结果。

   int index = Collections.binarySearch(myList, "value", getName());

感谢任何建议

【问题讨论】:

    标签: java list search arraylist


    【解决方案1】:

    要以更具可扩展性的方式执行此操作,而不是简单地迭代/过滤对象,请参阅类似问题的答案:How do you query object collections in Java (Criteria/SQL-like)?

    【讨论】:

      【解决方案2】:

      我知道匿名内部类不再流行,但是当 Java 8 到来时,您可以创建如下内容:

      1.- 创建一个迭代集合的搜索方法,并传递一个告诉您是否要返回您的对象的对象。

      2.- 调用该方法并使用标准创建一个匿名内部类

      3.- 在单独的变量中获取新列表。

      类似这样的:

      result = search( aList, new Matcher(){ public boolean matches( Some some ) { 
        if( some.name().equals("a")) { 
           return true;
        }
      }});
      

      这是一个工作演示:

      import java.util.*;
      class LinearSearchDemo { 
        public static void main( String ... args ) { 
            List<Person> list = Arrays.asList(
                                        Person.create("Oscar", 0x20),
                                        Person.create("Reyes", 0x30),
                                        Person.create("Java", 0x10)
                                );
      
            List<Person> result = searchIn( list, 
                    new Matcher<Person>() { 
                        public boolean matches( Person p ) { 
                            return p.getName().equals("Java");
                    }});
      
            System.out.println( result );
      
            result = searchIn( list, 
                    new Matcher<Person>() { 
                        public boolean matches( Person p ) { 
                            return p.getAge() > 16;
                    }});
      
            System.out.println( result );
      
        }
        public static <T> List<T> searchIn( List<T> list , Matcher<T> m ) { 
            List<T> r = new ArrayList<T>();
            for( T t : list ) { 
                if( m.matches( t ) ) { 
                    r.add( t );
                }
            }
            return r;
        }
      }
      
      class Person { 
        String name;
        int age;
      
        String getName(){ 
            return name;
        }
        int getAge() { 
            return age;
        }
        static Person create( String name, int age ) { 
            Person p = new Person();
            p.name = name;
            p.age = age;
            return p;
        }
        public String toString() { 
            return String.format("Person(%s,%s)", name, age );
        }    
      }
      interface Matcher<T> { 
        public boolean matches( T t );
      }
      

      输出:

      [Person(Java,16)]
      [Person(Oscar,32), Person(Reyes,48)]
      

      【讨论】:

      • 这很酷,我给你加分了,但实际上它并不比“冗长”的代码简洁多少.. for(n:list){if(n.getAge()>16 t. add(n);} 在某些情况下比匿名类短..
      【解决方案3】:

      我熟悉的一个库是 Guava——您可以编写它的 Predicate 以从 Iterable 中提取项目。无需对集合进行预分类。 (这反过来意味着它是 O(N),但它很方便。)

      【讨论】:

        【解决方案4】:

        如果对象是不可变的(或者您至少知道它们的名称不会改变),您可以使用 HashMap 创建索引。

        您必须填写地图并保持更新。

        Map map = new HashMap();
        
        map.put(myObject.getName(), myObject);
        ... repeat for each object ...
        

        然后您可以使用map.get("Some name"); 使用您的索引进行查找。

        【讨论】:

          【解决方案5】:

          如果您只是作为一次性操作需要查找其 getName() 为特定值的对象,那么可能没有太多魔法:循环遍历列表,对每个对象调用 getName(),对于那些匹配的,将它们添加到您的结果列表中。

          如果 getName() 是一项昂贵的操作,并且如果给定对象肯定不会返回匹配值,那么还有一些其他的先验方法,那么显然你可以在循环时构建这个“过滤”。

          如果您经常需要为给定的 getName() 获取对象,请保留 [result of getName()->object -> 匹配列表] 的索引(例如在 HashMap 中)。您需要决定如何以及是否需要让这个“索引”与实际列表保持同步。

          另请参阅使用 binarySearch() 但保持列表保持不变的另一个提议。这样,插入比使用映射和未排序列表更昂贵,但如果与查找相比插入不频繁,那么它的优点是只需要维护一个结构。

          【讨论】:

          • 那么使用 hashmap 会加快速度吗?对象列表中的数据很少会改变(比如每周只有一次),我已经按照您最初建议的方式完成了它,但对速度不满意,所以基本上我试图找到一种方法来加快速度..谢谢
          • 如果变化频繁,只在变化时排序。我会自己使用 Map 而不是二进制搜索。使用地图可能更快,但只有一种方法可以找到:-)
          • 我在想如果我只是把我需要的“外键”放在像Map &lt;String foreignkey, foo&gt; 这样的地图中,这会更快,因为基本上有一个外键字段我只需要检查值如果它匹配,这将使它比循环整个列表更快,对吗?
          • 在纸面上,地图速度更快,可扩展性更强。从本质上讲,检索时间,无论您的系统上是什么,都将是恒定的,无论地图中有多少元素;对于二分搜索,元素数量每增加一倍,时间就会增加一些常数。但是,如果任何一个都足够快满足您的目的,那么归根结底是哪种结构更容易为您管理。
          • 我认为你真的会做很多地图,例如 Map 用于 getName() 和 Map 用于 getAge 等......你甚至可能想要考虑一些如果你真的在做大量不同“键”的查找,那么就像 hsqldb 这样的内存数据库。
          【解决方案6】:

          看看binarySearch that takes a comparator

          public static int binarySearch(List list, T键, 比较器 c)

          所以你会做这样的事情:

          class FooComparator
              implements Comparator<Foo>
          {
              public int compare(T a, T b)
              {
                  return (a.getName().compareTo(b.getName());
              }
          }
          
          int index = Collections.binarySearch(myList, "value", new FooComparator());
          

          您首先需要对课程列表进行排序(Collections.sort 也需要一个 Comaprator...)。

          【讨论】:

          • 当然如果添加了列表,还需要根据这个比较器在合适的地方添加,这样列表才能保持有序。如果不经常添加,这可能是比使用地图更好的解决方案,因为您只维护一个结构。
          • 特别是,这仅在您首先使用将用于搜索的相同比较器对列表进行排序时才有效。
          猜你喜欢
          • 2012-10-19
          • 2011-02-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-08-10
          • 1970-01-01
          相关资源
          最近更新 更多