2014-06-05 112 views
6

我決定採取功能性做法,產生一個字符串或隨機字符,到目前爲止,我想出了這一點,應該執行比拳擊更好,然後用StringJoiner作爲收藏家:如何使用Stream API混洗流?

Random random = new Random(); 
String randomString = IntStream.concat(
     random.ints(8, 'a', 'z'), 
     random.ints(8, 'A', 'Z') 
) 
     .collect(
       StringBuilder::new, 
       (sb, i) -> sb.append((char)i), 
       (sb1, sb2) -> sb1.append(sb2) 
     ).toString(); 

我想生成從az或AZ範圍的16個字符的流,我遇到的問題是我不知道如何洗牌兩個流。

我知道,我使用IntStream.concat這裏,這將只是在連接兩個流,我正在尋找以下任一操作:

  • 靜態運營商像IntStream.concat合併流時,做的洗牌。
  • sorted()這樣的流操作符。

在我看來,這兩種方式都是可行的,但是我特別感興趣的是如何讓運營商如sorted()。這裏的關鍵是它是一個有狀態的運算符,因爲它需要在運行之前看到整個流,有沒有辦法在流序列中注入有狀態的運算符?

到目前爲止,運營,不包括所需要的工作洗牌他們,似乎在Java 8

回答

10

你想得扭曲;-)

Random random = new Random(); 
String randomString=random.ints(16, 0, 26*2).map(i->(i>=26? 'a'-26: 'A')+i) 
    .collect(StringBuilder::new, 
      StringBuilder::appendCodePoint, StringBuilder::append) 
    .toString(); 

既然你已經有了一個隨機值的來源,那麼調用shuffle函數就沒有意義了(這對於來說效果不佳)。

請注意,您也可以在String定義允許的字符明確,並使用選擇它們: random.ints(16, 0, allowed.length()).map(allowed::charAt)

類似的模式適用於從隨機存取List選擇。


更新:

StringBuilder allowed= 
    IntStream.concat(IntStream.rangeClosed('a', 'z'), IntStream.rangeClosed('A', 'Z')) 
    .collect(StringBuilder::new, 
      StringBuilder::appendCodePoint, StringBuilder::append); 
String randomString=random.ints(16, 0, allowed.length()).map(allowed::charAt) 
    .collect(StringBuilder::new, 
      StringBuilder::appendCodePoint, StringBuilder::append) 
    .toString(); 

(注:如果你想有代碼清楚地顯示出允許的字符的兩個範圍的性質可以與上述char選擇解決方案結合您的Stream.concat的方法,我取代rangerangeClosed,我懷疑是否符合你的初衷,但它不會做什麼Random.ints(…, 'a', 'z')會做)。

+1

它不幸的是擺脫了明確的'''''''和'''''Z''範圍。 – skiwi

+0

不一定。看到我更新的答案。 – Holger

+0

這不是洗牌。這允許重複。洗牌意味着保留原始元素,而不是其順序。 –

1

功能的方法這可能不是優雅,你希望以不appropiate,但它的工作原理:

final Random random = new Random(); 
String randomString = IntStream.concat(random.ints(8, 'a', 'z'+1), random.ints(8, 'A', 'Z'+1)) 
    .collect(StringBuilder::new, (sb, i) -> { 
     int l = sb.length(); 
     if (l == 0) { 
     sb.append((char) i); 
     } else { 
     int j = random.nextInt(l); 
     char c = sb.charAt(j); 
     sb.setCharAt(j, (char) i); 
     sb.append(c); 
     } 
    }, (sb1, sb2) -> sb1.append(sb2)).toString(); 
System.out.println(randomString); 

或者你可以這樣做:

final String randomString = random.ints(100, 'A', 'z' + 1) 
     .filter(i -> i <= 'Z' || i >= 'a').limit(16) 
     .collect(StringBuilder::new, (sb, i) -> sb.append((char) i), 
       StringBuilder::append).toString();