How to shuffle a stream using the Stream API?
You are thinking too twisted
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();
Since you already have a source of random values there is no point in calling for a shuffle function (which would not work very well with streams).
Note that you also could define the allowed chars in a String
explicitly and select them using:
random.ints(16, 0, allowed.length()).map(allowed::charAt)
Similar pattern applies to selecting from a random access List
.
Update: If you want to have code clearly showing the two ranges nature of the allowed characters you can combine your Stream.concat
approach with the char
selection solution described above:
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();
(Note: I replaced range
with rangeClosed
which I suspect to match your original intentions while it does not do what Random.ints(…, 'a', 'z')
would do).
This is probably not as elegant as you hoped for but it works:
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);
Alternatively you could do this:
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();