Use Java 8 functional programming to generate letter sequences

Source: Internet
Author: User
Tags stream api

Use Java 8 functional programming to generate letter sequences

 

Using functional programming to generate letter sequences in Java 8 is a big challenge. Lukas Eder happily accepts this challenge and will tell us how to use Java 8 to generate ABC sequences-of course, it is not a bad way.

I was overwhelmed by an interesting question raised by "mip" on Stack Overflow. The problem is:

1 2 3 I am looking for a way to generate the following letter sequences:A, B, C, ..., Z, AA, AB, AC, ..., ZZ.

You should be able to quickly recognize that this is the Excel spreadsheet header, which looks exactly as follows:

So far, no answer has been implemented using Java 8 functional programming, so I accept this challenge. I will use jOO λ because the Stream API of Java 8 does not provide enough functionality to complete this task. I admit that I am wrong-thank you very much for the interesting answers to this question ).

First, we use functions to break down this algorithm. We need the following components:

1. A reproducible alphabet.

2. an upper limit, such as the number of letters to be generated. If the sequence ZZ is required to be generated, the upper bound is 2.

3. A method that combines letters in the alphabet with previously generated letters into a cartesian product.

Let's take a look at the Code:

1. generate an alphabet

We can write the alphabet like this, for example:

1 List<String> alphabet = Arrays.asList("A", "B", ..., "Z");

But this is poor. We use jOO λ instead:

1 2 3 4 List<String> alphabet = Seq     .rangeClosed('A', 'Z')     .map(Object::toString)     .toList();

The code above generates A closed range from Character A to Z where Java-8-Stream-speak contains the upper boundary), maps the character to A string, and finally converts it to A list.

So far, everything is fine. Now:

2. Use the upper boundary:

The required character sequences include:

1 A .. Z, AA, AB, .. ZZ

However, it should be easy to think of extending this requirement to generate the following character sequences or more:

1 A .. Z, AA, AB, .. ZZ, AAA, AAB, .. ZZZ

Therefore, we will use rangeClosed () again ():

1 2 3 4 // 1 = A .. Z, 2 = AA .. ZZ, 3 = AAA .. ZZZ Seq.rangeClosed(1, 2)    .flatMap(length -> ...)    .forEach(System.out::println);

This method generates a separate stream for each length in the range [1 .. 2], and then combines the streams into a stream. The essence of flatMap () is similar to the nested loop in imperative programming.

3. Merge letters into a Descartes

This is the tricky part: we need to merge characters and the number of occurrences. Therefore, we will use the following stream:

1 2 3 4 5 Seq.rangeClosed(1, length - 1)    .foldLeft(Seq.seq(alphabet), (s, i) ->        s.crossJoin(Seq.seq(alphabet))         .map(t -> t.v1 + t.v2))     );

We use rangeClosed () again to generate the value in the range [1 .. length-1. FoldLeft () and reduce () are basically the same. The difference is that foldLeft () ensures that the order in the stream is from "Left to right" and does not need to be correlated using the fold function.

On the other hand, this is an easy-to-understand word: foldLeft () represents only one loop command. The "Origin" of the loop is the initialization value of the loop) is a complete alphabet Seq. seq (alphabet )). Now, in the range [1 .. the value in length-1] generates a Cartesian Product crossJoin () to generate a new alphabet, and then each merged letter is combined into a separate string t. v1 and t. v2 ).

This is the entire process.

Merge the preceding content

The following is A simple program that prints A. Z, AA. ZZ, AAA. ZZZ to the console:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 import org.jooq.lambda.Seq; public class Test {     public static void main(String[] args) {         int max = 3;         List<String> alphabet = Seq             .rangeClosed('A', 'Z')             .map(Object::toString)             .toList();         Seq.rangeClosed(1, max)            .flatMap(length ->                Seq.rangeClosed(1, length - 1)                   .foldLeft(Seq.seq(alphabet), (s, i) ->                       s.crossJoin(Seq.seq(alphabet))                        .map(t -> t.v1 + t.v2)))            .forEach(System.out::println);     } }

Statement

This is indeed not the optimal algorithm for this problem. In Stack Overflow, an anonymous user provides the best implementation method.

1 2 3 4 5 6 7 8 9 10 import static java.lang.Math.*; private static String getString(int n) {     char[] buf = new char[(int) floor(log(25 * (n + 1)) / log(26))];     for (int i = buf.length - 1; i >= 0; i--) {         n--;         buf[i] = (char) ('A' + n % 26);         n /= 26;     }     return new String(buf); }

Needless to say, this algorithm is much faster than the previous functional algorithm.

 

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.