【问题标题】:Java - Search performantly for subset of String in String listJava - 在字符串列表中高效搜索字符串的子集
【发布时间】:2014-10-12 14:07:39
【问题描述】:

我想搜索一个字符串列表并返回包含搜索字符串的值。

列表可能如下所示(最多可包含 1000 个条目)。尽管不能保证它始终是字母,然后是数字。可能只有数字,只有单词,甚至两者都混在一起:

entry 1
entry 2
entry 3
entry 4
test 1
test 2
test 3
tst 4

如果用户确实搜索了 1,则应返回这些:

entry 1
test 1

情况是用户有一个搜索栏,可以输入一个搜索字符串。此搜索字符串用于在列表中进行搜索。

如何才能高效地做到这一点?

目前,我有:

for (String s : strings) {
    if (s.contains(searchedText))   result.add(s);
}

这是 O(N) 并且非常慢。尤其是当用户一次输入多个字符时。

【问题讨论】:

  • 您只想搜索数字还是字母和数字的任意组合?

标签: java android string search


【解决方案1】:

也许我不明白你的问题,但正如你所知,Java,字符串对象是不可变的,但也可以表示字符的集合(数组)。因此,您可以做的一件事是使用更好的算法执行搜索,例如 binary_searchAho-CorasickRabin–KarpBoyer–Moore string searchStringSearchone of these。您也可以考虑使用一些性能更好的Abstract_data_types(散列、树等)。

【讨论】:

    【解决方案2】:

    如果你使用流,这很简单:

    final List<String> items = Arrays.asList("entry 1", "entry 2", "entry 3", "test 1", "test 2", "test 3");
    final String searchString = "1";
    final List<String> results = items.parallelStream()  // work in parallel
            .filter(s -> s.contains(searchString))       // pick out items that match
            .collect(Collectors.toList());               // and turn those into a result list
    results.forEach(System.out::println);
    

    注意parallelStream(),它将导致使用所有可用的 CPU 过滤和遍历列表。

    在您的情况下,当用户扩展搜索词(在键入时)以减少需要过滤的项目数量时,您可以使用results,因为如果“s”匹配结果中的所有项目,则所有那些match 'se' 将是结果的子列表。

    【讨论】:

    • 如果不考虑更正,重复使用结果可能很危险,但可以显着提高性能。
    • 我绑定的是Android,没有Java 8。
    • 抱歉,我错过了关于 Android 的那部分。
    【解决方案3】:

    如果您不使用任何其他结构,则执行速度不会比查看数据更快。这需要 O(N)。 如果你能做一些准备,比如建立文本索引,你可以提高搜索的性能。一般信息:http://en.wikipedia.org/wiki/Full_text_search。如果您可以对您的数据做出一些假设(例如最后一个符号是数字,并且您将只按它进行搜索),那么创建这样的索引将很容易。

    【讨论】:

      【解决方案4】:

      根据字符串中数字的上限,如果您不担心空间,请使用 ArrayLists 数组,其中数组索引是字符串的编号:

      ArrayList<String>[] data = new ArrayList<String>[1000];
      for ( int i = 0; i < 1000; i++ )
        data[i] = new ArrayList<String>();
      
      //inserting data
      int num = Integer.parseInt(datastring.substring(datastring.length-1));
      data[i].add(datastring);
      
      //getting all data that has a 1
      for ( String s: data[1] )
        result.add(s);
      

      在尝试将新值放入其中时,使用 Hashmap 会覆盖以前的映射值。
      即如果 1 映射到条目,那么您尝试将 1 映射添加到测试,该条目将被替换为测试。

      另一个想法是,您可以只计算每个数字的字符串数,这样当您搜索时,您就知道要查找多少个,因此一旦找到所有字符串,您就停止搜索:

      int[] str_count = new int[1000];
      for ( int i = 0; i < 1000; i++ )
        str_count[i] = 0;
      
      //when storing data into the list:
      int num = Integer.parseInt(datastring.substring(datastring.length-1));
      str_count[i]++;
      
      //when searching the list for 1s:
      int count = str_count[1];
      for (String s : strings) {
        if (s.contains(searchedText))   
          result.add(s);
        if (result.size() == count)
          break;
      }
      

      虽然第一个想法会快得多,但它会占用更多空间。然而,第二个想法占用的空间更少,最坏的情况仍然会搜索 O(N)。

      【讨论】:

      • 为什么使用 Vector 而不是 ArrayList?请记住,Vector 是同步的,因此速度较慢。
      • 我会解决的。我没有偏好,因为我没有考虑过。
      猜你喜欢
      • 2018-05-22
      • 2019-04-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-11-28
      • 1970-01-01
      • 2019-05-29
      • 1970-01-01
      相关资源
      最近更新 更多