【问题标题】:Is there any way to know if an arraylist contains a piece of text?有什么方法可以知道数组列表是否包含一段文本?
【发布时间】:2012-11-18 03:14:47
【问题描述】:

我有一个包含多个项目的数组列表。假设它们是:“深棕色”、“蓝色”、“绿色”、....

有什么方法可以查找我的某些项目中是否有字符串“DARK”?我知道 contains 会这样做,但只有在字符串完全正确的情况下才会这样做。我的想法是寻找一个以我的项目之一开头但没有最后一个字符的文本。

我想像这样循环:

for(int i=0;i<arraylist.size;i++){
  String s = arraylist.get(i);
  if (s.startsWith(mytext)){
   do something
  }
}

但它似乎是一个非常慢的方法,因为 arraylist 可以包含很多元素。有更好的想法吗?

编辑

只是为了确保您理解我的观点。我想知道我的数组列表中的一个项目是否包含一个以某些文本开头的元素并获取该元素的完整文本。 ArrayList.contains 是一个布尔值。如果我需要检索信息,我将不得不使用 IndexOf 左右,但如果我输入“棕色”,这个函数会给我 null

编辑 2

这是给你的 auselen:

Arraylist(5000个元素左右):

  • “大卫的猫在他的卧室里”
  • “我喜欢月亮”
  • “我想去火星旅行”
  • “我的球是红色的”
  • “他们总是忘记南极”
  • ...

我想知道是否有一个以“I want to”开头的元素,然后检索该元素的其余部分。

【问题讨论】:

  • “但这似乎是一个非常缓慢的方法,因为..” ..分析器表明这是瓶颈发生的地方。 (大约是该句子唯一有效的结尾。)
  • 最适合我认为您正在做的事情的数据结构是 prefix tree,即所谓的 trie。
  • 对 i 也是正确的,下面说 trie 是最好的,但是你有几百万字吗?没有然后看我的回答
  • 对数组列表进行排序并使用某种分治法搜索
  • 有多少个字符串?

标签: java arrays string arraylist contains


【解决方案1】:

这里是一个函数示例,您可以使用它来获取每个项目。这个速度并不是真正的增加。由于这是一个数组列表,因此没有真正的好方法来做到这一点。有更好的数据结构来搜索字符串的一部分。

    public class RegionMatchesDemo {
public static void main(String[] args) {
    String searchMe = "Green Eggs and Ham";
    String findMe = "Eggs";
    int searchMeLength = searchMe.length();
    int findMeLength = findMe.length();
    boolean foundIt = false;
    for (int i = 0; 
         i <= (searchMeLength - findMeLength);
         i++) {
       if (searchMe.regionMatches(i, findMe, 0, findMeLength)) {
          foundIt = true;
          System.out.println(searchMe.substring(i, i + findMeLength));
          break;
       }
    }
    if (!foundIt)
        System.out.println("No match found.");
  }
}

【讨论】:

  • 这和问题完全没有关系。
【解决方案2】:

要么像以前那样做,要么变得更复杂。 有一种叫做“trie”的搜索结构,但这很复杂。

通过将 a-z 数组指向已排序的 ArrayList 中第一个字母的起始位置,您可以获得一点好处。然后你只需要在以相同字母开头的单词中进行搜索。

【讨论】:

  • 不超过 5000 个元素。我不确定最终数组列表的大小是多少。您说的第二个数组是个好主意,因为数组已排序,但并不能说服我。我从没想过用数组列表做这么愚蠢的事情需要额外的代码。无论如何,如果没有更好的主意,我想我会尝试一下
  • 是的,要么做你的第一个解决方案,5000 并不多,或者如果你想要最快的,拿我的。 (一个 trie 是复杂的)。
【解决方案3】:

或者您可以使用完全不同的方法。并包装 ArrayList 并检查 list.add() 是否匹配。并将其存储在某个 var 中以便快速访问。但是,如果您要搜索多个值,那么这种方法根本不好:)。

【讨论】:

    【解决方案4】:

    这似乎是一个很慢的方法,因为arraylist可以包含很多元素。

    比如,一百万?

    Nov 30, 2012 10:05:20 AM test.t100.t001.ArrayListSpeed main
    INFO: Creating entries.
    Nov 30, 2012 10:05:21 AM test.t100.t001.ArrayListSpeed main
    INFO: Searching..
    Nov 30, 2012 10:05:21 AM test.t100.t001.ArrayListSpeed main
    INFO: Searching 'dark' 333716
    Nov 30, 2012 10:05:21 AM test.t100.t001.ArrayListSpeed main
    INFO: Searching 'light' 333333
    Nov 30, 2012 10:05:22 AM test.t100.t001.ArrayListSpeed main
    INFO: Searching 'plain' 332951
    

    代码

    package test.t100.t001;
    
    import java.util.ArrayList;
    import java.util.Random;
    import java.util.logging.Level;
    import java.util.logging.Logger;
    
    public class ArrayListSpeed {
    
        public static String[] PREFIX = {"Dark ", "Light ", "Plain "};
        public static String[] COLOR = {"Red", "Green", "Blue"};
    
        public static String getColor(Random r) {
            int val = r.nextInt(COLOR.length);
            return COLOR[val];
        }
    
        public static String getPrefix(Random r) {
            int val = r.nextInt(PREFIX.length);
            return PREFIX[val];
        }
    
        public static int countPrefixes(ArrayList<String> list, String prefix) {
            int count = 0;
            for (String val : list) {
                if (val.toLowerCase().startsWith(prefix.toLowerCase())) {
                    count++;
                }
            }
            return count;
        }
    
        public static void main(String[] args) {
            Logger logger = Logger.getAnonymousLogger();
            ArrayList<String> list = new ArrayList<String>();
            Random r = new Random();
            logger.log(Level.INFO, "Creating entries.");
            for (int ii=0; ii<1000000; ii++) {
                list.add( getPrefix(r) + getColor(r) );
            }
            logger.log(Level.INFO, "Searching..");
            logger.log(Level.INFO, 
                    "Searching 'dark' " + countPrefixes(list,"dark"));
            logger.log(Level.INFO, 
                    "Searching 'light' " + countPrefixes(list,"light"));
            logger.log(Level.INFO, 
                    "Searching 'plain' " + countPrefixes(list,"plain"));
        } 
    }
    

    【讨论】:

    • 毫秒记录器会很棒;-)
    • 我不知道它会查找多少次,因为我没有包含所有项目的数组列表,但我很害怕,因为它是用于 android 设备的,所以处理能力有限并且必须在不到一秒的时间内(用户无法注意到应用程序正在“寻找解决方案”。它必须在按下按钮时注意到有解决方案)。当我查看我的代码时,我认为“这真的很脏。一定有一个简单的方法”所以我发布了这个。我看不出你的解决方案和我的解决方案有什么不同。
    • “我看不出你的解决方案和我的有任何区别。” 我的可以编译并运行,因此可以扫除像 这样的错误语句“它似乎是一种非常缓慢的方法”。在不到 2 秒的时间内搜索了 300 万条条目。 5000 应该花费
    • 我的代码也可以编译。我的意思是我和你一样有一个循环,我们都检查了所有的arraylist。当我写这个问题时,我在考虑 Java 是否有类似 String a = "example" + anyletter 的东西(就像在 sql 中一样),然后 indexof 会很好地检索它
    • 在手机上运行代码并将数字提供给我们.. 这可能有助于证明您所说的。到目前为止,这似乎是“噪音”。
    【解决方案5】:

    将字符串保存在 sorted(!) 数组中,并使用 binarysearch 查找前缀的插入点。比赛将在那个时候进行,如果有的话。

    如果这是 O(log n) 而不是 O(n) 的性能,您应该会发现它要快得多,尤其是对于大型数据集。

    import static org.junit.Assert.assertEquals;
    import java.util.Arrays;
    import org.junit.Test;
    
    public class ContainsPrefix {
    
        public static String findWithPrefix(String[] data, String prefix) {
            int n = Arrays.binarySearch(data, prefix);
            if (n < 0) n = -1 - n;
            // Loop here if you want to find all matches ...
            if (!data[n].startsWith(prefix)) return null;
            return data[n];
        }
    
    
        @Test
        public void shouldFindStringWithPrefix() {
            String[] data = { //
                    "David's cat is in his bedroom", //
                    "I like the moon", //
                    "I want to travel to Mars", //
                    "My ball is red", //
                    "They always forget about Antarctida", //
                    "..." //
                };
            Arrays.sort(data);
            String found = findWithPrefix(data, "I want to");
            assertEquals("I want to travel to Mars", found);
    
        }
    
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-05-26
      • 1970-01-01
      • 2017-05-04
      • 2013-03-21
      • 1970-01-01
      • 2019-06-24
      相关资源
      最近更新 更多