【问题标题】:Java looping through array - OptimizationJava循环遍历数组 - 优化
【发布时间】:2013-10-26 13:31:57
【问题描述】:

我有一些 Java 代码可以按照预期的方式运行,但它需要一些时间 - 几秒钟 - 即使作业只是循环遍历数组。

输入文件是一个 Fasta 文件,如下图所示。我正在使用的文件是 2.9Mo,还有一些其他的 Fasta 文件最多可以占用 20Mo。

在代码中,我试图通过三组循环遍历它,例如:AGC TTT TCA ......基地。示例:

AGC - Ser / CUG Leu / ...等

那么代码有什么问题?有什么办法可以做得更好吗?有什么优化吗?遍历整个 String 需要一些时间,可能只需几秒钟,但需要找到更好的方法。

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;

public class fasta {
    public static void main(String[] args) throws IOException {

        File fastaFile;
        FileReader fastaReader;
        BufferedReader fastaBuffer = null;
        StringBuilder fastaString = new StringBuilder();

        try {
            fastaFile = new File("res/NC_017108.fna");
            fastaReader = new FileReader(fastaFile);
            fastaBuffer = new BufferedReader(fastaReader);
            String fastaDescription = fastaBuffer.readLine();
            String line = fastaBuffer.readLine();

            while (line != null) {
                fastaString.append(line);
                line = fastaBuffer.readLine();
            }

            System.out.println(fastaDescription);
            System.out.println();
            String currentFastaAcid;

            for (int i = 0; i < fastaString.length(); i+=3) {
                currentFastaAcid = fastaString.toString().substring(i, i + 3);
                System.out.println(currentFastaAcid);
            }

        } catch (NullPointerException e) {
            System.out.println(e.getMessage());
        } catch (FileNotFoundException e) {
            System.out.println(e.getMessage());
        } catch (IOException e) {
            System.out.println(e.getMessage());
        } finally {
            fastaBuffer.close();
        }

    }

}

【问题讨论】:

  • 我不知道,为什么它花费的时间比预期的要长,我唯一可以提到的是 StringBuilder 内置了“substring”方法,所以你可以避免总是创建一个字符串( toString()) 在取出子序列之前。

标签: java string for-loop bioinformatics fasta


【解决方案1】:
currentFastaAcid = fastaString.toString().substring(i, i + 3);

请替换为

currentFastaAcid = fastaString.substring(i, i + 3);

StringBuilder 的 toString 方法每次调用它时都会创建 String 对象的新实例。它仍然包含所有大字符串的副本。如果您直接从 StringBuilder 调用子字符串,它将返回子字符串的一个小副本。 如果你真的不需要 System.out.println,也可以删除它。

【讨论】:

    【解决方案2】:

    这里的重要因素是您每次都在新字符串上调用子字符串。

    相反,直接在字符串生成器上使用子字符串

    for (int i = 0; i < fastaString.length(); i+=3){
        currentFastaAcid = fastaString.substring(i, i + 3);
        System.out.println(currentFastaAcid);
    }
    

    另外,不是每次都打印 currentFastaAcid,而是将其保存到一个列表中并在最后打印此列表

    List<String> acids = new LinkedList<String>();
    
    for (int i = 0; i < fastaString.length(); i+=3){
        currentFastaAcid = fastaString.substring(i, i + 3);
        acids.add(currentFastaAcid);
    }
    
    System.out.println(acids.toString());
    

    【讨论】:

      【解决方案3】:

      除了调试输出之外,您的主要问题肯定是,您正在创建一个新字符串,并在循环的每次迭代中从文件中完全读取数据:

      currentFastaAcid = fastaString.toString().substring(i, i + 3);
      

      fastaString.toString() 将在每次迭代中给出相同的结果,因此是多余的。把它放在循环之外,你肯定会节省几秒钟的运行时间。

      【讨论】:

        【解决方案4】:

        除了建议的串行代码优化外,我将进行并行处理以进一步减少时间。如果你有非常大的文件,你可以将读取文件和处理读取行的工作分成不同的线程。这样,当一个线程忙于从大文件中读取下一行时,其他线程可以处理读取的行并在控制台上打印它们。

        【讨论】:

          【解决方案5】:

          如果你删除

          System.out.println(currentFastaAcid);
          

          for 循环中的行,您将获得相当可观的时间。

          【讨论】:

            猜你喜欢
            • 2019-07-10
            • 1970-01-01
            • 1970-01-01
            • 2016-05-25
            • 2015-09-22
            • 2011-10-21
            • 1970-01-01
            • 2014-06-04
            相关资源
            最近更新 更多