搜索字符串列表(100 000个字符串):如果存在%,如何搜索x字符

时间:2018-08-01 10:35:07

标签: java android algorithm arraylist

我正在用Java编写一个android应用程序,我需要显示ListView

但是在创建ListView之前,我需要用数据填充Adapter。 我有一个ArrayList的字符串,我想通过ArrayList搜索该EditText

我的Arraylist有10万多个条目。

  • 我想在输入ABC时从ArrayList获得ABC。
  • 我想在输入A_C时从ArrayList中获取ABC,AAC,ACC,ADC等信息,因此在这种情况下_需要替换一个字符。它也应该适用于彼此相邻而不是彼此相邻的多个下划线。
  • 键入A%C时,我想从ArrayList获取ABC,AAC,ACC,ADC,ABAC,ABBC ...,因此在这种情况下,%需要替换多个字符。它也应该适用于多个%而不是彼此相邻。我认为这与Windows中的星号*相同。

希望您能提供帮助。

3 个答案:

答案 0 :(得分:2)

严重的未回答:请考虑不要在您的应用中执行此操作。

当您处理如此大量的数据时,您确实不希望这种处理发生在(可能很便宜的)手机硬件上。迟早,有些人会在硬件不足的情况下使用您的应用程序,然后他们会抱怨“该应用程序非常慢”。

含义:考虑在某种后端服务中执行此操作。然后,使用内置的技术来处理大量文本数据,例如solr。因此,是的,应用程序可能会在您键入内容时向您的服务发送字符串,并且服务会发回建议,列表等。

答案 1 :(得分:1)

您可以尝试以下方法。首先,我们将创建一个与您的搜索词匹配的正则表达式,然后按照Korashen的建议,使用paralellStream()过滤列表。

正则表达式(?<=[_%])|(?=[_%])将在_%处拆分字符串,同时保留定界符。例如,如果拆分"A_B",结果将是["A","_","B"],而不是["A","B"]

private static List<String> filterByTerm(List<String> list, String term) {
    StringBuilder regexBuilder = new StringBuilder();
    String[] array = term.split("(?<=[_%])|(?=[_%])");
    for(String s : array) {
        switch(s) {
        case "_":
            regexBuilder.append(".");
            break;
        case "%":
            regexBuilder.append(".*");
            break;
        default:
            regexBuilder.append(Pattern.quote(s));
        }
    }

    String regex = regexBuilder.toString();
    return list.parallelStream().filter(s -> s.matches(regex)).collect(Collectors.toList());
}

已验证的最低示例:

List<String> input = new ArrayList<>();
input.add("ABC");
input.add("AAC");
input.add("ACC");
input.add("ADC");

String term = "AB_";

filterByTerm(input, term).forEach(System.out::println);

给出ABC的输出。

答案 2 :(得分:1)

ArrayList字符串不是此任务的正确数据结构。搜索此类列表的唯一方法是遍历所有列表,这将很慢。您需要一个数据结构来支持您正在执行的查询。这样做的代价可能是增加了内存占用。

字符的树形结构似乎可以正常工作。您将用下面的树表示单词AAB,ABA和ABB:

     A
    / \
   A   B
  /   / \
 B   A   B

我也非常同意GhostCat,您可能不想这样做。

下面是一个快速实现。我不能保证它会完美或最佳地工作-这是对可能的证明,而不是可用于生产的代码。我尚未使用大型数据集对其进行过测试。

它仅支持下划线规则,但对其进行修改应足够简单,以支持多字符匹配。


一个通用接口,由根节点和实际char节点共同实现,并包含默认搜索实现:

interface CharTree
{
    List<CharNode> getChildren();

    default Optional<CharNode> getChild(char character)
    {
        return getChildren().stream()
            .filter(ch -> ch.getCharacter() == character)
            .findFirst();
    }

    default void search(final String pattern, final StringBuilder builder, final Set<String> results)
    {
        if (pattern.isEmpty())
        {
            results.add(builder.toString());
            return;
        }

        char character = pattern.toCharArray()[0];
        final List<CharNode> candidates;
        if (character == '_')
        {
            candidates = getChildren();
        }
        else
        {
            candidates = getChild(character)
                .map(Collections::singletonList)
                .orElse(Collections.emptyList());
        }

        for (final CharNode node : candidates)
        {
            builder.append(node.getCharacter());
            node.search(pattern.substring(1, pattern.length()), builder, results);
            builder.deleteCharAt(builder.length() - 1);
        }
    }
}

基本的根实现,带有静态方法来构建树:

class Root implements CharTree
{
    private Root() { }

    @Getter private List<CharNode> children = new ArrayList<>();

    public static Root buildTree(final List<String> words)
    {
        final Root root = new Root();
        for (final String word : words)
        {
            CharTree current = root;
            for (char character : word.toCharArray())
            {
                Optional<CharNode> node = current.getChild(character);
                if (node.isPresent())
                {
                    current = node.get();
                }
                else
                {
                    final CharNode tmp = new CharNode(character);
                    current.getChildren().add(tmp);
                    current = tmp;
                }
            }
        }
        return root;
    }
}

简单字符节点(注释来自龙目岛)

@Data
@ToString(of = "character")
class CharNode implements CharTree
{
    private final char character;
    private List<CharNode> children = new ArrayList<>();
}

一些单元测试,以防有人担心:

@Test
public void one()
{
    final List<String> words = Arrays.asList("aaa", "bbb", "ccc");
    final CharTree root = Root.buildTree(words);

    final Set<String> results = new HashSet<>();
    root.search("aaa", new StringBuilder(), results);

    Assert.assertEquals(1, results.size());
    Assert.assertTrue(results.contains("aaa"));
}

@Test
public void two()
{
    final List<String> words = Arrays.asList("aaa", "aba", "abb");
    final CharTree root = Root.buildTree(words);

    final Set<String> results = new HashSet<>();
    root.search("a_a", new StringBuilder(), results);

    Assert.assertEquals(2, results.size());
    Assert.assertTrue(results.contains("aaa"));
    Assert.assertTrue(results.contains("aba"));
}

@Test
public void three()
{
    final List<String> words = Arrays.asList("aaa", "aba", "abb");
    final CharTree root = Root.buildTree(words);

    final Set<String> results = new HashSet<>();
    root.search("___", new StringBuilder(), results);

    Assert.assertEquals(3, results.size());
    Assert.assertTrue(results.contains("aaa"));
    Assert.assertTrue(results.contains("aba"));
    Assert.assertTrue(results.contains("abb"));
}
相关问题