dmfs / jems

Java gems, a collection of Java utilities.
Apache License 2.0
5 stars 2 forks source link

Alternating Iterable #97

Open dmfs opened 7 years ago

dmfs commented 7 years ago

In order to create a new Iterable which contains the alternating values of two other Iterables I want an Alternating Iterable.

Usage :

Iterable<String> result = new Alternating<>(new Seq<>("1", "2", "3"), new Seq("a", "b", "c"));

Iteration starts with the first Iterable and stops as soon as either of the Iterables is empty. So the result of the Iterable above would look like this:

"1", "a", "2", "b", "3"

"c" would not be iterated because the first Iterable is already "empty" at that time.

When being used with a ConstantGenerator (#96) this could look like

Iterable<String> result = new Alternating<>(new Seq<>("1", "2", "3"), new ConstantGenerator<>(":"));

which would result in:

"1", ":", "2", ":", "3"
dmfs commented 7 years ago

I realized there are 3 different modes of a "truely" alternating Iterable (an Iterable in which every two elements of one iterator are separated by one from the other iterator). They differ in how the Iterator ends when one of the sources ends.

The following examples illustrate all 3 modes:

Alternated1( Seq("1", "2", "3"), Seq())
-> ()   // empty 
Alternated2( Seq("1", "2", "3"), Seq())
-> ()   // empty 
Alternated3( Seq("1", "2", "3"), Seq())
-> ("1")

Alternated1( Seq("1", "2", "3"), Seq("a"))
-> ("1", "a")
Alternated2( Seq("1", "2", "3"), Seq("a"))
-> ("1", "a")
Alternated3( Seq("1", "2", "3"), Seq("a"))
-> ("1", "a", "2")

Alternated1( Seq("1", "2", "3"), Seq("a", "b"))
-> ("1", "a", "2", "b" )
Alternated2( Seq("1", "2", "3"), Seq("a", "b"))
-> ("1", "a", "2", "b" )
Alternated3( Seq("1", "2", "3"), Seq("a", "b"))
-> ("1", "a", "2", "b", "3" )

Alternated1( Seq("1", "2", "3"), Seq("a", "b", "c"))
-> ("1", "a", "2", "b", "3")
Alternated2( Seq("1", "2", "3"), Seq("a", "b", "c"))
-> ("1", "a", "2", "b", "3", "c")
Alternated3( Seq("1", "2", "3"), Seq("a", "b", "c"))
-> ("1", "a", "2", "b", "3", "c")

Alternated1( Seq("1", "2", "3"), Seq("a", "b", "c", "d"))
-> ("1", "a", "2", "b", "3")
Alternated2( Seq("1", "2", "3"), Seq("a", "b", "c", "d"))
-> ("1", "a", "2", "b", "3", "c")
Alternated3( Seq("1", "2", "3"), Seq("a", "b", "c", "d"))
-> ("1", "a", "2", "b", "3", "c")

Ideally we can distinguish these cases with meaningful names. Some options are Alternated, Folded, Staggered, Interlaced.

dmfs commented 5 years ago

I've come to the conclusion that it's best to have just one Alternated Iterable which takes an argument which defines the "mode". This argument should get the "hasNext" value of the two Iterators and something which indicates which Iterator is the next one to be iterated.