How to shuffle a stream using Stream API?

I decided to use a functional approach to create strings or random characters, so far I have come up with this, it should work better than boxing, and then use StringJoiner as a collector:

 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(); 

I want to create a 16 character stream, starting from az or AZ, the problem is that I don't know how to shuffle both streams.

I know that here I am using IntStream.concat , which simply combines both streams. I am looking for one of the following:

  • A static statement, such as IntStream.concat , that shuffles when combining streams.
  • Stream operator, for example sorted() .

Both methods are viable, in my opinion, however I am especially intrigued by how to make the operator the same sorted() . The key point here is that it is a state operator, since it needs to see the entire stream before it can work, is there any way to introduce the state operator into the sequence of threads?

Until now, operations, with the exception of the necessary work to shuffle them, seem to be unsuitable for a functional approach in Java 8.

+6
source share
2 answers

You are 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, it makes no sense to call a shuffle function (which does not work well with threads).

Note that you can also explicitly define valid characters in String and select them using: random.ints(16, 0, allowed.length()).map(allowed::charAt)

A similar pattern is used to select from random access List .


Update. If you want the code to clearly show the nature of valid characters in two ranges, you can combine your Stream.concat approach with the char decision 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 matches your original intentions until it does what Random.ints(…, 'a', 'z') will do Random.ints(…, 'a', 'z') ).

+10
source

This is probably not as elegant as you hoped, 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 can 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(); 
+1
source

Source: https://habr.com/ru/post/970379/


All Articles