在 ArrayList 中搜索对象
Posted
技术标签:
【中文标题】在 ArrayList 中搜索对象【英文标题】:Searching For Object In ArrayList 【发布时间】:2012-02-28 12:25:59 【问题描述】:我是 Java 的相对新手,正在为我的编程课程构建一个应用程序,用户可以在其中输入、删除、搜索或编辑学生列表(一个由整数 ID 号、字符串姓氏组成的对象,和双倍GPA)。到目前为止,我已经成功地允许用户输入、删除或编辑条目。现在,100 多名学生的列表在一个 ArrayList 中(每个学生都是一个带有三个参数的学生对象)。
我的问题是我不知道一种有效的方法来允许用户根据 ID 号、姓氏或 GPA(以及将来可能的 GPA 范围)搜索特定学生。我一直在研究 Big-O 表示法并想使用二分搜索,因为如果学生列表继续增长,这将是一个很好的实践,也是一个更好的选择。到目前为止,对于二分搜索,我们正在使用带有 while 循环的 high/low/mid 方法(如果这表明我当前的技能水平)。
所以这是我的问题:
根据此条件搜索特定学生的有效方法是什么?我不是在寻找代码或解决我的困境的答案。我真的在寻找 Java 程序员用来做这种事情的技术或技巧的名称,特别是如果这些技术可以与其他面向对象的编程语言一起使用。
【问题讨论】:
您是根据完全匹配还是类似匹配(即:'Gar' 匹配 'Garcia')进行搜索? 最好是准确地搜索名称(忽略大小写)。对 ID 号的搜索必须准确。对于 GPA,我希望它返回所有适用的内容,但前提是它对我的技能水平来说并不过分复杂。 【参考方案1】:我建议查看HashMap 数据结构。它允许您将元素存储在映射到某个键的集合中,以便以后可以通过相同的键检索它们。在您的示例中,您可以使用不同的哈希映射来搜索不同的字段。哈希映射的键是字段(即:ID、姓氏或 GPA),值是相应的学生。对于不区分大小写的搜索,请确保在保存对象和检索对象之前将键(姓氏)转换为小写。
存储ID:
Map<String, Student> idToStudent;
键:“23213233”,值:“某位学生”;
要考虑重复名称或 gpa,然后使用以下类型的映射:
Map<String, List<Student>> lastNameToStudents;
键:“smith”,值:[“John Smith”、“Bob Smith”等]
Map<Double, List<Student>> gpaToStudents:
键:“2.4”,值:[“学生 1”、“学生 2”等];
注意,为了简洁起见,我使用了学生姓名的字符串表示,但实际上这些表示Student
实例。
【讨论】:
很好的信息。绝对是我会调查的。谢谢。 投票。但是重名和GPA会是个问题。 @ggreiner 没有重复的问题,我不能给你的答案投票两次:) 顺便说一句:Guava Multimap 是为这样的结构设计的:'Multimap对于二分搜索,您需要按照搜索条件对列表进行排序。
您可以维护三个不同的列表,按您需要的三个不同标准排序:
ArrayList<Student> sortedByName;
ArrayList<Student> sortedByGpa;
ArrayList<Student> sortedById;
public List<Student> getStudentByName(String name)
return binarySearchOnName(sortedByName, name);
public List<Student> getStudentByGpa(double gpa)
return binarySearchOnGpa(sortedByGpa, gpa);
...
请注意,当您在 ArrayList 中插入一个新 Student 时,您还应该将该 Student 插入到另一个已排序的 ArrayList 中的正确位置。 (当然,您可以使用二分搜索来执行此操作。)
【讨论】:
【参考方案3】:您需要重复还是任意排序?如果没有,请考虑使用 TreeSet 或 HashSet。 TreeSet 提供 O(log(n)) 访问/插入/删除并自动对其元素进行排序(因此迭代它会按排序顺序获取元素。HashSet 提供分期 O(1) 访问/插入/删除,但迭代发生在一些随机顺序(您无法控制)。其中一种听起来是实现目标的最简单方法。
如果您需要按成员搜索,您可能需要一个 HashMap/TreeMap,只要您不介意只获得完全匹配。如果您需要按成员搜索多个成员,您可能需要多个映射,每个要搜索的键一个映射。如果您要使用 ArrayLists 并且想要比 O(n) 查找更好,那么无论如何您都需要多个列表(每个查找参数 1 个列表,按该参数排序)。
最后,O(n) 查找将是迄今为止最简单的。只要列表不会变得太大(想想 10000 个元素而不是 100 个元素),性能就会很好,并且这种方法可以最大限度地减少存储开销。您不希望过早优化——在性能成为问题之前,最好的技术就是遍历列表。
【讨论】:
其实我还没有研究过HashSets或者TreeSets,但是谢谢你的建议。我一定会调查这些。谢谢!【参考方案4】:所以我看到一个普遍问题的三个问题。一般问题是您希望能够根据某些标准进行搜索,这三个问题是每个问题的具体情况。因此,唯一保证唯一的字段是学生 ID 字段。这允许我们覆盖 equals + hashcode 方法。我们希望这是我们用来确定相等性的值(至少在这个非常简单的示例中)。通过这样做,您将通过以下调用公开一种无需排序即可在列表中进行搜索的机制:
list.contains(Student);
现在就名称而言,由于不能保证这个值是唯一的,我们想做类似的事情:
matchedStudents = new ArrayList<Student>();
for(Student currentStudent : studentList)
if(currentStudent.getName().equalsIgnoreCase(searchString)
matchedStudents.add(currentStudent);
return matchedStudents;
就 GPA 而言,我们基本上会重复上面的循环,只是使用 where GPA == searchCriteria 调用。
话虽如此,应该可以编写这样的函数:
function searchStudent(String searchString, String type)
//type is one of: GPA, name, ID
switch(type)
case gpa:
case id:
case name:
这应该让你开始。
【讨论】:
以上是关于在 ArrayList 中搜索对象的主要内容,如果未能解决你的问题,请参考以下文章
Dom4j解析语音数据XML文档(注意ArrayList多次添加对象,会导致覆盖之前的对象)
源码面经Java源码系列-ArrayList与LinkedList