2013-03-02 173 views
1

嗨,我正在讀取一個文本文件並將每行(用逗號分隔)保存到一個數組中。唯一的問題是數組中的大多數元素都是double值,其中兩個元素是字符串。作爲這個的結果,我不得不使數組成爲一個String []數組。由於這個原因,只要我想對數組中的double值執行一些方程式,我必須首先將它們解析爲雙精度值。我從字面上運行這些方程的1000多次迭代,因此我的代碼不斷地將字符串解析爲雙精度。這是一個代價高昂的方式,它會減慢我的程序。有沒有更好的方法可以將字符串數組中的值轉換爲double值,或者在保存文本文件中的行時應該採取更好的方法嗎?由於Java - 將字符串轉換爲雙倍字符串的最有效方法

這裏是陣列的一個看起來像我已經從文本文件中讀取後:

String[] details = {"24.9", "100.0", "19.2" , "82.0", "Harry", "Smith", "45.0"}; 

我現在需要乘以第一2種元素,並添加到第3的總和,第4和第七個要素。換句話說,我只使用數字內容(被ofcourse保存爲字符串)

double score = (Double.parseDouble(details[0]) * Double.parseDouble(details[1])) + Double.parseDouble(details[2]) + Double.parseDouble(details[3]) + Double.parseDouble(details[6]); 

我必須爲文本文件(超過1000行)每一行做到這一點。由於這個,我的程序運行非常緩慢。有沒有更好的方法,我可以將字符串值轉換爲雙精度?還是有更好的方法,我應該把它們放在首位呢?

編輯:我已經使用Profiler來檢查代碼的哪一部分是最慢的,它確實是我上面

+0

爲什麼不只是將它們** **轉換一次**並存儲結果? – 2013-03-02 16:38:47

+8

調用'Double.parseDouble()'5000次不會讓你的程序運行速度非常慢。 – NPE 2013-03-02 16:38:58

+0

@OliCharlesworth - 每條線都不一樣。因此涉及到不同的值 – Matt9Atkins 2013-03-02 16:40:15

回答

4

下面是一個生成輸入文件的例子,如您所描述的輸入文件長度爲10000行,然後將其讀回並進行發佈的計算並將結果輸出到stdout。在讀取文件時,我特別禁用了任何緩衝,以獲得最差的讀取性能。正如其他人所建議的,我也沒有做任何緩存。整個過程(包括生成文件,進行計算和打印結果)始終需要大約520-550毫秒。這很難「緩慢」,除非你爲數百或數千個文件重複這個過程。如果你看到性能差異很大,那麼也許是硬件問題。發生故障的硬盤可能會使讀取性能幾乎沒有變化。

import java.io.*; 
import java.util.Random; 

public class ReadingDoublesFromFileEfficiency { 
    private static Random random = new Random(); 

    public static void main(String[] args) throws IOException { 
     long start = System.currentTimeMillis(); 
     String filePath = createInputFile(); 
     BufferedReader reader = new BufferedReader(new FileReader(filePath), 1); 
     String line; 
     while ((line = reader.readLine()) != null) { 
      String[] details = line.split(","); 
      double score = (Double.parseDouble(details[0]) * Double.parseDouble(details[1])) + Double.parseDouble(details[2]) + Double.parseDouble(details[3]) + Double.parseDouble(details[6]); 
      System.out.println(score); 
     } 
     reader.close(); 
     long elapsed = System.currentTimeMillis() - start; 
     System.out.println("Took " + elapsed + " ms"); 
    } 

    private static String createInputFile() throws IOException { 
     File file = File.createTempFile("testbed", null); 
     PrintWriter writer = new PrintWriter(new FileWriter(file)); 
     for (int i = 0; i < 10000; i++) { 
      writer.println(randomLine()); 
     } 
     writer.close(); 
     return file.getAbsolutePath(); 
    } 

    private static String randomLine() { 
     return String.format("%f,%f,%f,%f,%s,%s,%f", 
       score(), score(), score(), score(), name(), name(), score()); 
    } 

    private static String name() { 
     String name = ""; 
     for (int i = 0; i < 10; i++) { 
      name += (char) (random.nextInt(26) + 97); 
     } 
     return name; 
    } 

    private static double score() { 
     return random.nextDouble() * 100; 
    } 
} 
2

你會做的更好,以創建合適的對象,並存儲值中的代碼這將給你兩個主要的好處,1)你的代碼會更快,因爲你避免不必要的重新計算double值,2)你的代碼會更清晰,因爲這些字段將被命名而不是像details[0]這樣的調用,它完全不清楚[0]指的是。

由於2)我不知道是什麼領域應該是,所以很明顯你的類將有所不同,但這個想法是一樣的:

public class PersonScore { 
    private double[] multipliers = new double[2]; 
    private double[] summers = new double[3]; 
    private String first; 
    private String last; 

    // expects a parsed CSV String 
    public PersonScore(String[] arr) { 
     if(arr.length != 7) 
      throw new InvalidArgumentException("Must pass exactly 7 fields"); 
     multipliers[0] = Double.parseDouble(arr[0]); 
     multipliers[1] = Double.parseDouble(arr[1]); 
     summers[0] = Double.parseDouble(arr[2]); 
     summers[0] = Double.parseDouble(arr[3]); 
     summers[0] = Double.parseDouble(arr[6]); 
     first = arr[4]; 
     last = arr[5]; 
    } 

    public double score() { 
     double ret = 1; 
     for(double mult : multipliers) 
      ret *= mult; 
     for(double sum : summers) 
      ret += sum; 
     return ret; 
    } 

    public String toString() { 
     return first+" "+last+": "+score(); 
    } 
} 

通知有一個額外的好處,那得分法現在更加健壯。上面的實現對我們想要使用的字段進行了硬編碼,但通過解析和存儲這些字段作爲結構內容,我們能夠實現更具可讀性,更具可擴展性的分數計算方法。

相關問題