2014-06-05 28 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();