【问题标题】:Effective way to build a list of tokens from multiple strings in Java在 Java 中从多个字符串构建标记列表的有效方法
【发布时间】:2013-04-01 01:47:16
【问题描述】:

我正在寻找一种有效的方法来获取从多个字符串中提取的字符串标记列表(例如,使用空格分隔符)。

例子:

String s1 = "My mom cook everyday";
String s2 = "I eat everyday";
String s3 = "Am I fat?";  
LinkedList<String> tokens = new LinkedList<String>();   
//any code to efficiently get the tokens

//final result is tokens  make of a list of the following tokens:
//"My", "mom", "cook", "everyday", "I", "eat", "everyday", "Am", "I", "fat?".

现在

  1. 我不确定LinkedList 是最有效的收集类(Apache Commons、Guava,它们能帮上忙吗?)!
  2. 我打算使用来自 Apache Commons 的 StringUtils,但 split 方法返回一个数组!因此,我应该使用 for 循环从 split 返回的字符串对象数组中提取字符串。效率高吗:我不知道,split 创建了一个数组!
  3. 我从 Guava 读到了 Splitter,但 this post 指出 StringUtils 在实践中更好。
  4. 来自Java.utilScanner 怎么样。它似乎没有分配任何额外的数据结构。不是吗?

请绘制最有效的 Java 解决方案,即使使用其他广泛使用的库,例如 GuavaApache Commons

【问题讨论】:

  • 关于#3 - 你引用的帖子恰恰相反:总之,我想我大部分时间仍然会使用Splitter。在小型列表中,性能差异可以忽略不计,Splitter 使用起来感觉更好。我仍然对结果感到惊讶,如果您要拆分很多字符串并且性能是一个问题,那么可能值得考虑切换回 Commons StringUtils。 另外,Splitter 很多,很多 比 String#split 或 Apache Commons 解决方案更强大。
  • 为什么对优化如此感兴趣?
  • @PaulVargas 因为我有数千个字符串要从大文本中进行标记。
  • @Xaerxess 我读了这篇文章:它并没有相反的说法。他的结论是“如果您要拆分大量字符串并且性能是一个问题,那么可能值得考虑切换回 Commons StringUtils”。我的目标是……
  • 您的意思是阅读大文本文件吗?

标签: java string guava tokenize apache-commons


【解决方案1】:

如果您有较小的字符串并且性能不是问题,您可以像这样将splitaddAll 结合起来:

String s1 = "My mom cook everyday";
String s2 = "I eat everyday";
String s3 = "Am I fat?";  
List<String> tokens = new ArrayList<String>();  

tokens.addAll(Arrays.asList(s1.split("\\s+")));
tokens.addAll(Arrays.asList(s2.split("\\s+")));
tokens.addAll(Arrays.asList(s3.split("\\s+")));

System.out.println(tokens);

但是,如果性能问题,这里有一个替代解决方案:

由于没有定义如何获取这些长文本,我假设它们来自InputStream。看看这个方法的性能是否足以满足您的需求:

public List<String> readTokens(InputStream is) throws IOException{
    Reader reader = new InputStreamReader(is);
    List<String> tokens = new ArrayList<String>();
    BufferedReader bufferedReader = new BufferedReader(reader);
    String line = null;
    while((line = bufferedReader.readLine()) != null){
        String[] lineTokens = StringUtils.split(line, " "); 
        for(int i = 0 ; i < lineTokens.length ; i++){
            tokens.add(lineTokens[i]);
        }
    }
    return tokens;
}

关于你关于ArrayListLinkedList在末尾插入的声明,也许你应该阅读this

【讨论】:

  • 我读到从 String 中拆分并不是一个真正有效的解决方案。这就是为什么,例如,Apache Commons 带有StringUtils.split!也许是因为它使用了模式......
  • 你的弦真的那么大吗?因为您不应该担心不成问题的性能
  • 此外,当要插入的元素数量较多时,ArrayList 的效率不如 LinkedList!实际上,ArrayList 只是一个数组的“包装器”,它带有一个默认大小的数组,一旦超出默认大小,您就必须创建一个新数组并将旧值复制到新数组中!非常无效!
  • 无效是一个非常主观的术语。您需要说明您的性能需求和要求。我的回答是基于你的例子。对于您所说的,我的回答非常有效。也许一个更真实的例子可以帮助我们得出更好的解决方案
  • @mat_boy:“非常无效!”这听起来可能效率低下,但在实践中,它通常仍然比LinkedList 更有效。总体而言,它仍然是线性时间,当使用 memcpy 之类的工具完成时,将一个数组复制到另一个数组实际上非常快(这就是 Java 在幕后所做的)。 LinkedList 所涉及的额外间接寻址可能很昂贵。
【解决方案2】:
     import java.util.ArrayList;
     import java.util.Collections;


    public class stringintotoken {
String s="my name is tarun bharti";
ArrayList <String> words=new ArrayList<String>();
public static void main(String[] args)
{
    stringintotoken st=new stringintotoken();
    st.go();
}
public void go()
{
    wordlist();
    System.out.println(words);
    Collections.sort(words);
    System.out.println(words);

}
public void wordlist()
{
    String[] tokens=s.split(" ");
    for(int i=0;i<tokens.length;i++)
    {
    words.add(tokens[i]);
    }
}

}

【讨论】:

    【解决方案3】:
    for (String str : Arrays.asList(s1, s2, s3)) {
      Iterables.addAll(tokens, Splitter.on(' ').split(str));
    }
    

    我会这样做。也就是说,对于几乎所有用例,ArrayList 优于 LinkedList;如果没有进一步的数据,我们真的无法判断您是否处于LinkedList 更可取的罕见情况之一。

    【讨论】:

      【解决方案4】:

      首先使用分隔符连接您的字符串(请参阅Join a string using delimiters)。那么:

       LinkedList<String> tokens = new LinkedList<String>();
       StringTokenizer st = new StringTokenizer(yourstr); // " " as a default delimiter
       while (st.hasMoreTokens()) {
           tokens.add(st.nextToken());
       }
      

      您是否正在寻找高效或高性能的解决方案(即您的约束/参考性能是什么)?

      【讨论】:

        【解决方案5】:

        或者只是Arrays.asList((s1 + " " + s2 + " " + s3).split("\\s+"))

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2023-03-03
          • 2021-12-15
          • 2013-06-02
          • 2012-01-29
          • 2011-05-24
          • 2015-08-16
          • 2018-11-28
          • 1970-01-01
          相关资源
          最近更新 更多