在List <t> </t>中搜索值的最快且优化的方法

时间:2015-01-23 03:28:00

标签: java

我有List<Person> persons = new ArrayList<Person>(),此列表的大小为100+。我想检查此列表中是否包含特定的personID对象。目前我正在这样做:

for(Person person : persons) 
{
    for(Long pid : listOfIDs) 
    {
        if(person.personid == pid) 
        {
            // do somthing 
        } 
        else
        {
            // do somthing 
        }
    } // end of inner for
} 

但我不想遍历persons中每个元素的listOfIDs列表。我想将HashMap的Person personid作为键,将Person对象作为值。因此,我只能遍历listOfIDs并检查contains()

还有其他办法吗?

2 个答案:

答案 0 :(得分:1)

如果列表变长,嵌套循环的实现将无法很好地扩展。您将要执行的操作数量是两个列表长度的乘积。

如果您的列表中至少有一个按ID排序,则可以使用二进制搜索。这将是对嵌套循环的改进。

构建Map是一个好主意,并且可以很好地扩展。使用此技术,您将遍历Persons列表一次以构建映射,然后迭代ID列表一次以执行查找。确保使用人数初始化HashMap的大小(因此您不必在将人员放入Map中时重新进行重新散列)。这是一个非常可扩展的选项,不需要对任何列表进行排序。

如果BOTH列表碰巧按ID排序,那么您还有另一个有吸引力的选择:共同走下两个列表。您将从两个列表的开头开始,并在具有最小ID的列表中前进。如果ID相等,那么您执行业务逻辑以找到具有该ID的人员并在两个列表中前进。一旦你到达任何一个列表的末尾,你就完成了。

答案 1 :(得分:0)

Java的Collections提供了一个非常快速的二进制搜索,但它假设您正在搜索列表的成员。您可以使用您的ID标准实现自己的:

Collections.sort(persons, (p1, p2) -> p1.personID - p2.personID);
if (binarySearch(persons, id)) {
    ...
}

boolean binarySearch(List<Person> personList, Long id) {
    if (personList.empty())
        return false;
    long indexToTest = personList.size() / 2;
    long idToTest = personList.get(indexToTest).personID;
    if (idToTest < id) 
        return binarySearch(personList.subList(indexToTest + 1, personList.size());
    else if (idToTest > id)
        return binarySearch(personList.subList(0, indexToTest));
    else
        return true;
}

如果您不想对列表进行排序,那么您可以将其复制到排序列表并搜索:对于大型列表,它仍然比迭代它快得多。事实上,这与保持单独的哈希映射非常相似(尽管哈希映射可能更快)。

如果您必须迭代,那么您至少可以使用并行流来利用多个核心,如果您拥有它们:

if (persons.parallelStream().anyMatch(p -> p.personID == id)) {
    ...
}