【问题标题】:How to search in a List of Java object如何在 Java 对象列表中搜索
【发布时间】:2012-10-19 19:00:57
【问题描述】:

我有一个对象列表,并且列表非常大。对象是

class Sample {
    String value1;
    String value2;
    String value3;
    String value4;
    String value5;
 }

现在我必须在列表中搜索对象的特定值。说如果value3=='three'我必须返回那些对象(我的搜索并不总是基于value3)

名单是

List<Sample> list = new ArrayList<Sample>();

什么是有效的方法?

谢谢。

【问题讨论】:

  • 你自己有没有尝试过?
  • @Tichodroma 他说他有一份这些物品的清单。
  • @Tichodroma 我认为他的意思是List&lt;Sample&gt;,这是一个列表
  • 如果您正在寻找大量对象的效率,我会考虑排序对象的层次结构,然后是一种有效的算法来跳过不可能。

标签: java list search collections


【解决方案1】:

如果您总是根据value3 进行搜索,您可以将对象存储在地图中:

Map<String, List<Sample>> map = new HashMap <>();

然后,您可以使用 key = value3 和 value = 具有相同 value3 属性的 Sample 对象列表填充地图。

然后就可以查询地图了:

List<Sample> allSamplesWhereValue3IsDog = map.get("Dog");

注意:如果没有 2 个Sample 实例可以具有相同的value3,您可以简单地使用Map&lt;String, Sample&gt;

【讨论】:

  • No.. 我的搜索并不总是基于 value3.. 它可以基于 object 中的任何字段
  • @Sun 这是性能和内存占用量之间的折衷问题:每个字段维护一个映射会更快但使用更多内存,每次需要搜索时循环遍历列表会更慢但使用更少的内存。
  • 或者,如果你的对象结构是扁平的(只有字符串字段),你可以看看 Guava 的表——不过我从来没有用过。
【解决方案2】:

我修改了这个列表并在示例中添加了一个列表试试这个

伪代码

Sample {
   List<String> values;
   List<String> getList() {
   return values}
}



for(Sample s : list) {
   if(s.getString.getList.contains("three") {
      return s;
   }
}

【讨论】:

  • 我的列表很大.. 我正在寻找有效的搜索。这是唯一可能的方法吗?
  • 您可以将值组织为哈希图,以避免检查 Sample 中的每个条目...
【解决方案3】:

由于您的列表是ArrayList,因此可以假定它是未排序的。因此,没有办法搜索比 O(n) 更快的元素。

如果可以,您应该考虑将您的列表更改为Set(以HashSet 作为实现),并为您的示例类指定一个特定的Comparator

另一种可能性是使用HashMap。您可以将数据添加为Sample(请以大写字母开头类名)并使用您要搜索的字符串作为关键字。然后你可以简单地使用

Sample samp = myMap.get(myKey);

如果每个键可以有多个样本,请使用Map&lt;String, List&lt;Sample&gt;&gt;,否则使用Map&lt;String, Sample&gt;如果您使用多个键,则必须创建多个包含相同数据集的地图。因为它们都指向相同的对象,所以空间应该不是什么大问题。

【讨论】:

    【解决方案4】:

    你可以试试Apache Commons Collections

    有一个类 CollectionUtils 允许您通过自定义 Predicate 选择或过滤项目。

    你的代码应该是这样的:

    Predicate condition = new Predicate() {
       boolean evaluate(Object sample) {
            return ((Sample)sample).value3.equals("three");
       }
    };
    List result = CollectionUtils.select( list, condition );
    

    更新:

    java8 中,使用 Lambda 和 StreamAPI 这应该是:

    List<Sample> result = list.stream()
         .filter(item -> item.value3.equals("three"))
         .collect(Collectors.toList());
    

    好多了!

    【讨论】:

    • CollectionUtils 方法给了我这个错误:java.lang.NoSuchMethodError: No interface method stream()Ljava/util/stream/Stream; in class Ljava/util/List; or its super classes (declaration of 'java.util.List' appears in /system/framework/core-libart.jar,我不能使用 Lambdas,因为 Android SDK 不支持 Java 8。
    • @Yankee 遇到了同样的问题。你让它工作了吗?
    • @ono 我使用了 Java8 方法,效果很好。但请记住,您必须在 Gradle 文件中添加一些 Java 8 特定的依赖项
    • @Yankee 我有 gradle 进口,但我仍然得到它。你有这两个对吗? compileOptions {sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8}
    • @ono 是的。这些在我的 build.gradle(Module:app) 中,在我的 build.gradle(项目)中有classpath 'me.tatarka:gradle-retrolambda:3.4.0'
    【解决方案5】:

    使用 Java 8

    使用Java 8,您可以简单地将您的列表转换为stream,以便您编写:

    import java.util.List;
    import java.util.stream.Collectors;
    
    List<Sample> list = new ArrayList<Sample>();
    List<Sample> result = list.stream()
        .filter(a -> Objects.equals(a.value3, "three"))
        .collect(Collectors.toList());
    

    注意

    • a -&gt; Objects.equals(a.value3, "three")lambda expression
    • resultListSample 类型
    • 速度非常快,每次迭代都不会强制转换
    • 如果您的过滤器逻辑变得更重,您可以使用list.parallelStream() 而不是list.stream() (read this)


    Apache Commons

    如果你不能使用Java 8,你可以使用Apache Commons库并写:

    import org.apache.commons.collections.CollectionUtils;
    import org.apache.commons.collections.Predicate;
    
    Collection result = CollectionUtils.select(list, new Predicate() {
         public boolean evaluate(Object a) {
             return Objects.equals(((Sample) a).value3, "three");
         }
     });
    
    // If you need the results as a typed array:
    Sample[] resultTyped = (Sample[]) result.toArray(new Sample[result.size()]);
    

    注意:

    • 每次迭代都会有一个从 ObjectSample 的演员表
    • 如果您需要将结果输入为Sample[],则需要额外的代码(如我的示例所示)



    奖励:nice blog article 谈论如何在列表中查找元素。

    【讨论】:

    • 有点可悲的是,在大多数情况下未能完成给定任务的答案得到了 13 个赞。请重新考虑应该如何比较字符串。
    • @Tom 到底是什么失败了?
    • @Toms 谢谢 :) Aswer 已相应编辑
    • 好吧a.value3.equals("three") 看起来更自然,但你的方式也是“空安全”,所以请保持:D。感谢您的更新,但我仍然想知道为什么没有其他人注意到它。由于您更喜欢其他语言(根据您的标签),我不能/不会责怪您,因为字符串比较在那里可能会有所不同。不过没关系,现在已经修好了。
    • @Tom "three".equals(((Sample) a).value3) 也可以工作并且是“null safe”。
    猜你喜欢
    • 2011-07-08
    • 2011-02-01
    • 2019-07-04
    • 1970-01-01
    • 1970-01-01
    • 2014-07-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多