【问题标题】:how to make search faster from contactList for given string如何从给定字符串的contactList中更快地搜索
【发布时间】:2016-06-26 09:05:11
【问题描述】:

我有 ContactList,其中包含名字和姓氏的联系人。我想按名字或姓氏进行搜索。

我已经编写了运行良好的代码,但我想在速度和内存方面改进搜索。

public class Contact implements Comparable<Contact> {

    private String firstName;
    private String lastName;
    private String name;

    public Contact(String name) {

        this.name = name;
        if (name.contains(" ")) {
            this.firstName = name.split("\\s+")[0];
            this.lastName = name.split("\\s+")[1];
        } else {
            this.firstName = name;
            this.lastName = "";
        }
    }

    public String getFirstName() {
        return firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public String getName() {
        return name;
    }

    @Override
    public String toString() {
        return "Contact{" + name + '}';
    }

    @Override
    public int compareTo(Contact contact) {
        System.out.println("in compareto");
        return this.name.compareToIgnoreCase(contact.getName());
    }
@Override
public int hashCode() {
    return (firstName.hashCode() * (lastName != null ? lastName.hashCode() : 0));
}

@Override
public boolean equals(Object obj) {
    if(obj == null)
        return false;
    if(!(obj instanceof Contact)) 
        return false;

    Contact other = (Contact) obj;
    if(! this.name.equalsIgnoreCase(other.name)) return false;

    return true;
}
  }

public class ContactService {

    private Set<Contact> contacts;

    public ContactService() {
        this.contacts =  new TreeSet<>();
    }

    public void addContact(String name) {
        Contact contact = new Contact(name);
        contacts.add(contact);
    }

    public void searchContact(String searchStr) {
        System.out.println(contacts);
        for (Contact contact : contacts) {
            if (contact.getName().equalsIgnoreCase(searchStr)||(searchStr.contains(" ") && contact.getName().contains(searchStr))) {
                System.out.println(contact.getName());
            } else if (contact.getFirstName().toLowerCase().startsWith(searchStr) || contact.getLastName().toLowerCase().startsWith(searchStr)) {
                System.out.println(contact.getName());
            }
        }
    }
}

请建议如何提高上述代码的性能。

【问题讨论】:

  • 您还可以使用索引来加快搜索速度。但是,您不必关心您的列表是否少于 10k 个元素,因为搜索时间非常短。
  • 我正在考虑添加索引,但我不确定我需要在哪个字段上放置索引 firstName 或 lastName?
  • @Kilanny 如您所见,用户可以按姓氏或名字搜索,所以我需要有两个索引,如果是,那么我们需要遍历列表两次。
  • 没有。您需要对 combined 名字和姓氏有索引。你也可以使用这个库lucene.apache.org/core
  • 我使用的是纯java代码,所以需要自己编写代码。

标签: java sorting search collections


【解决方案1】:

您可以使用java.util.HashMap 来存储联系人查找表以查找搜索词。

这个想法是用可能的搜索词(例如名字或名字的前三个字母)预先填充查找表。如果您的查找未返回任何匹配项,您始终可以执行完整搜索。如果您想要更强大的搜索,您可以查看 Apache Lucene 之类的内容。

例如

Map<String, Set<Contact>> contactLookup = new HashMap<>();

然后,您首先在地图中查找搜索词。这会将可能性缩小到一个小的集合,您可以使用上面使用的相同方法对其进行迭代。

您还可以查看来自 Guava 的 Multimap,它更优雅地提供了相同的功能。


顺便说一下(在不相关的注释上),当您覆盖 compareTo() 方法时,最好同时覆盖 equals() 以便 (x.compareTo(y)==0) == (x.equals(y)).

当您覆盖equals() 时,您还需要覆盖hashCode()

【讨论】:

  • 我没有预定义的搜索词,我的要求就像用户输入的联系人,如“Manoj Pathak”、“Manoj”。如果用户输入“Man”并点击搜索,则结果将为 Manoj Pathak Manoj 如果用户输入“Manoj”并点击搜索,则结果将为 Manoj(完全匹配)Manoj Pathak
  • 我已经更新了 equals 和 hashcode 的代码。需要在地图的键中设置什么值作为 searchTerm ??
  • 搜索词(键)可能是,例如:“manoj”、“man”、“pathak”。所有这些键都指向同一个联系人。
【解决方案2】:

我没有预定义的搜索词,我的要求就像用户 输入“Manoj Pathak”、“Manoj”等联系人。如果用户输入“Man”并且 点击搜索然后结果将是 Manoj Pathak Manoj 如果用户输入“Manoj” 然后点击搜索结果将是 Manoj (exact match) Manoj Pathak"

在这种情况下,我建议您实现 最长前缀匹配——Java 中基于 Trie 的解决方案,它在内部将使用 HashMap。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-12-02
    • 1970-01-01
    • 2020-09-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-20
    • 1970-01-01
    相关资源
    最近更新 更多