如何在 Java 对象列表中搜索

Posted

技术标签:

【中文标题】如何在 Java 对象列表中搜索【英文标题】:How to search in a List of Java object 【发布时间】: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>();

什么是有效的方法?

谢谢。

【问题讨论】:

你自己有没有尝试过? 为什么不创建 List? (docs.oracle.com/javase/1.4.2/docs/api/java/util/List.html) @Tichodroma 他说他有一份这些物品的清单。 @Tichodroma 我认为他的意思是List&lt;Sample&gt;,这是一个列表 如果您正在寻找大量对象的效率,我会考虑排序对象的层次结构,然后是一种有效的算法来跳过不可能。 【参考方案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”。

以上是关于如何在 Java 对象列表中搜索的主要内容,如果未能解决你的问题,请参考以下文章

如何在 json 对象的列表视图中搜索?

如何在具有多个字符串的数组列表中搜索对象并返回对象?

如何使用类成员搜索对象指针向量?

在 Java 中的对象列表中搜索字段 [重复]

如何使用 JpaRepository 和嵌套的对象列表进行搜索?

如何在java中的对象列表中查找重复项