2016-11-04 60 views
2

例如有ARA代碼用於從元件的限制量FINDE最小:java的8個流FINDE MIN/MAX限制

public int min(String s) { 
    return s.chars().map(this::mapToFactor).min().getAsInt(); 
} 

private int mapToFactor(int ch) { 
    switch(ch) { 
     case 'A': return 1; 
     case 'C': return 2; 
     case 'G': return 3; 
     case 'T': return 4; 
     default: return Integer.MAX_VALUE; 
    } 
} 

完全以只存在5號:1,2,3,4,Integer.MAX_VALUE的。當我們面對1時,可以跳過未來的迭代並返回結果。

public int min(String s) {  
    int min = Integer.MAX_VALUE; 
    for (Character ch : s.toCharArray()) { 
     int current = mapToFactor(ch); 
     if(current == 1) { 
      //How I can implement this in Java 8 stream style? 
      return 1; 
     } 
     if (current < min) { 
      min = current; 
     } 
     return min; 
    } 
} 

於是就如果我們的字符串將警惕大,那麼我們就可以顯著下跌性能通過使用Java 8個流而不是Java 7風格的跳躍iterrations如果1中找到。

您能否介紹一下如何在java 8流風格中編寫上述Java 7代碼?

+0

的可能的複製[上的流如何短路一個減少()操作?](http://stackoverflow.com/questions/32495069/how-to-short-circuit-a-reduce-流操作) – user140547

+0

[通過謂詞限制流]可能的重複(http://stackoverflow.com/questions/20746429/limit-a-stream-by-a-predicate) – the8472

回答

1

您可以運行Stream管道,該管道將搜索第一個出現的1。問題是,如果找不到1,則必須運行另一個Stream管道來查找最小值。

我能想到的另一種方法是運行Stream管道搜索第一1同時與peek保持目前最低:

int[] min = {Integer.MAX_VALUE}; // an int[] is used instead of int because the lambda 
           // expression cannot assign to a local variable 
return s.chars() // get an IntStream of the characters of s 
     .map(this::mapToFactor) // map the characters to 1-4 or Integer.MAX_VALUE 
     .peek(i -> {if (i<min[0]) min[0]=i;}) // modify min to contain the current minimum 
     .filter(i->i==1) // keep only 1s 
     .findFirst() // get the first 1 
     .orElse(min[0]); // if 1 is not found, return min[0] 

不那麼優雅,但直到第1發現處理的字符。

+0

.peek(i - > {if(i Alstresh

+2

@Alstresh'peek'不會在所有元素上運行。你可以在'peek'中添加一個'println'語句來查看它只處理元素,直到找到第一個元素。關於狀態變量,我確實說它不是很優雅。也許你會想到更好的東西。 – Eran

+0

但是,它與java 7不一樣,因爲1)首先,我們在所有流中使用ifde == 1 2)如果沒有找到,那麼迭代另一次以獲得最小值。它顯着增加了大字符串中'A'的複雜度。 – Alstresh

2

這是一個典型的過早優化案例。如果你關心績效,短暫迭代是最後一件事,你應該擔心。

讓我們看一下你的Java 7的變體:

for (Character ch : s.toCharArray()) { 

之前,你甚至開始你的迭代,你在呼喚String.toCharArray(),這在新分配char[]對象創建的String內容的副本。當然,要創建該副本,實現必須迭代整個String。在你自己的迭代開始之前。

然後,您將每個char值裝箱到一個Character對象中。由於不可識別的原因,因爲您的mapToFactor方法預計值爲int,所以Character對象必須在此處取消裝箱。

由於這些原因,在大多數環境中,s.chars().map(this::mapToFactor).min().getAsInt()可能比您的Java 7變體對大字符串要快得多。尤其是,當我們考慮具有A,即達到最小值1並且能夠提前退出時,情況並非總是如此。

通常,您應該測量實際執行時間,而不是猜測特定方法的假定缺陷。只有在遇到實際性能問題時纔開始嘗試優化。由於您對創建String的完整副本的原始代碼感到滿意,因此您應該對Stream版本感到滿意,並且不需要這些不必要的副本。在內聯和分析代碼之後,HotSpot優化器甚至可能會向Stream的內部循環添加提前終止條件。

3

以下解決方案使用Java 9中引入的takeWhile方法。儘管如此,代碼仍然是Java 8流風格。

public int min(String s) { 
    IntSummaryStatistics statistics = s.chars().map(this::mapToFactor) 
      .takeWhile(i -> i != 1).summaryStatistics(); 
    int index = (int)statistics.getCount(); 
    return (index < s.length() && s.charAt(index) == 'A') ? 1 : statistics.getMin(); 
}