16
ArrayList <String> list = new ArrayList(); 
list.add("behold");
list.add("bend");
list.add("bet");
list.add("bear");
list.add("beat");
list.add("become");
list.add("begin"); 

有一种方法可以搜索正则表达式 bea.* 并获取 ArrayList.indexOf 中的索引?

编辑:返回项目很好,但我需要比线性搜索性能更高的东西

4

7 回答 7

19

爱马仕的基础知识是正确的。如果你想要字符串而不是索引,那么你可以通过使用 Java 5 foreach 循环来改进:

import java.util.regex.Pattern;
import java.util.ListIterator;
import java.util.ArrayList;

/**
 * Finds the index of all entries in the list that matches the regex
 * @param list The list of strings to check
 * @param regex The regular expression to use
 * @return list containing the indexes of all matching entries
 */
List<String> getMatchingStrings(List<String> list, String regex) {

  ArrayList<String> matches = new ArrayList<String>();

  Pattern p = Pattern.compile(regex);

  for (String s:list) {
    if (p.matcher(s).matches()) {
      matches.add(s);
    }
  }

  return matches
}
于 2008-11-20T21:56:27.730 回答
8

有内置方法吗?从来没听说过。但是,自己做应该很容易。这是一些完全未经测试的代码,应该可以为您提供基本概念:

import java.util.regex.Pattern;
import java.util.ListIterator;
import java.util.ArrayList;

/**
 * Finds the index of all entries in the list that matches the regex
 * @param list The list of strings to check
 * @param regex The regular expression to use
 * @return list containing the indexes of all matching entries
 */
List<Integer> getMatchingIndexes(List<String> list, String regex) {
  ListIterator<String> li = list.listIterator();

  List<Integer> indexes = new ArrayList<Integer>();

  while(li.hasNext()) {
    int i = li.nextIndex();
    String next = li.next();
    if(Pattern.matches(regex, next)) {
      indexes.add(i);
    }
  }

  return indexes;
}

我可能对 Pattern 和 ListIterator 部分的使用有点错误(我从来没有使用过),但这应该给出基本的想法。您还可以在迭代器上执行简单的 for 循环而不是 while 循环。

于 2008-11-20T21:44:06.460 回答
4

一种选择是使用Apache Commons CollectionUtils “选择”方法。您需要创建一个 Predicate 对象(具有单个“评估”方法的对象,该方法使用正则表达式检查匹配并返回 true 或 false),然后您可以在列表中搜索匹配的项目。但是,它不会返回索引,它会返回一个包含项目本身的集合。

于 2008-11-20T21:44:45.710 回答
3

这是番石榴中的一个衬里:

final Iterable<String> matches = Iterables.filter(myStrings, Predicates.contains(Pattern.compile("myPattern")));

for (final String matched : matches) {
   ...
}
于 2014-06-30T09:38:39.367 回答
1

我不相信有这样做的 Java API 方式,也没有这样做的 Apache Commons 方式。然而,自己动手并不难。

于 2008-11-20T21:43:20.127 回答
0

当我们谈论大型列表时,将它们与 Java8 内置函数并行处理是有意义的。

@Test
public void testRegexPerformance()
{
    List<String> list = new ArrayList<>();
    list.add("behold");
    list.add("bend");
    list.add("bet");
    list.add("bear");
    list.add("beat");
    list.add("become");
    list.add("begin");
    for (int i = 0; i < 20; i++)
    {
        list.addAll(list);
    }
    System.out.println("Original list size: " + list.size());
    Instant startTime = Instant.now();
    List<String> results = testLoopApproach(list, "bea.*");
    Instant current = Instant.now();
    System.out.println("Found List size: " + results.size());
    System.out.println("Elapsed millis: " + (current.toEpochMilli() - startTime.toEpochMilli()));
    startTime = Instant.now();
    results = testStreamApproach(list, "bea.*");
    current = Instant.now();
    System.out.println("Found List size: " + results.size());
    System.out.println("Elapsed millis: " + (current.toEpochMilli() - startTime.toEpochMilli()));
}

private List<String> testStreamApproach(List<String> list, String regex)
{
    Predicate<String> pred = Pattern.compile(regex).asPredicate();
    return list.parallelStream().filter(pred).collect(Collectors.toList());
}

private List<String> testLoopApproach(List<String> list, String regex)
{
    Pattern p = Pattern.compile(regex);
    List<String> resulsts = new ArrayList<>();
    for (String string : list)
    {
        if (p.matcher(string).find())
        {
            resulsts.add(string);
        }
    }
    return resulsts;
}

and the results are:
Original list size: 7340032
Found List size: 2097152
Elapsed millis: 1785
Found List size: 2097152
Elapsed millis: 260
于 2021-01-27T12:08:19.333 回答
0

这将是线程复兴,但可能对某人有用。您可能不需要索引,可能下一步将对匹配正则表达式的项目做一些事情,因此您要求索引。但是您可以使用 Java8 流和 lambda 表达式:

  import java.util.regex.Pattern;
  import java.util.stream.Collectors;
  import java.util.List;

  ...

  var pattern = Pattern.compile(define);  // var is Java 10 feature

  List<String> list = originalList
      .stream()
      .filter(e -> pattern.matcher(e).matches())
      .collect(Collectors.toList());

您可以获取原始列表,将其转换为流,在其上运行过滤器,该过滤器运行 lambda 以匹配您的模式并将其转换回列表。但是您可以将其保留为流并使用另一个 lambda 表达式在其上运行 .foreach。

于 2019-10-07T16:11:52.323 回答