Skip to Content
Technical Articles
Author's profile photo Enno Wulff

My Solution to ABAP Community Code Contest `ABAP is excellent `

When Thomas Jung started the ABAP Community Code Challenge on February 28th, I first thought: Okay, this is not a big deal for an advanced programmer. But after the first solutions came up with “made it with 5 lines”, this really challenged me to do this in one line. After some help of my friends Peter Jaeckel and Łukasz Pęgiel I really made it in one line.

Solution

This is my solution:

"Explanation why ABAP has four unique characters and not three as expected:
"the second A is a cyrillic character which looks equal to "normal A" but has different unicode value

PARAMETERS p_text type string DEFAULT `ABАP  is excellent ` LOWER CASE.

"class (S)AP (C)ommunity (C)oding (C)hallenge (S)eries
CLASS scccs DEFINITION.
  PUBLIC SECTION.
    METHODS solve
      IMPORTING
        text          TYPE string
      RETURNING
        VALUE(result) TYPE string_table.
ENDCLASS.

CLASS test DEFINITION FOR TESTING RISK LEVEL HARMLESS DURATION SHORT.

  PUBLIC SECTION.
  PRIVATE SECTION.
    DATA cut TYPE REF TO scccs.
    METHODS setup.
    METHODS abap_is_excellent FOR TESTING.
    METHODS lorem_ipsum_dolor_sit_amet FOR TESTING.
    METHODS many_trailing_spaces FOR TESTING.
    METHODS many_leading_spaces FOR TESTING.
    METHODS many_space_in_the_middle FOR TESTING.
    METHODS complex FOR TESTING.

ENDCLASS.

CLASS scccs IMPLEMENTATION.
  METHOD solve.

    result = REDUCE string_table( "STRING_TABLE is the output...
             LET
               "clean the text from spaces
               text_wo_double_spaces = replace( regex = '(\s)(?=\1)' val = text  with = `` occ = 0 )
               "delete trailing and leading blanks
               cleaned_text = shift_left( val = shift_right( val = text_wo_double_spaces ) )
               "number of words is the number of blanks + 1
               num_words = count_any_of( val = cleaned_text sub = ` ` ) + 1 IN
             INIT
               "fill first result line with "number of words"
               lines = VALUE #( ( |Number of words: { num_words }| ) )
             " derive words via SEGMENT of cleaned string
             FOR word
             IN REDUCE string_table(
             INIT w = VALUE #( )
             "do read the words and store in table (equals SPLIT INTO TABLE)
             FOR i = 1 THEN i + 1 UNTIL i > num_words
             NEXT w = VALUE #( BASE w ( segment( val = cleaned_text index = i ) ) ) )
             NEXT lines = VALUE #(
               "transfer word-string to result table (BASE for keeping existing lines)
               BASE lines ( |Number of unique characters in the word: { word } - {
                    "now calculate number of distinct characters in each word
                    lines( REDUCE string_table(
                      "prepare the character table
                      INIT chars = VALUE string_table( )
                      "do aas many times as the word has characters; pos is the offset for current character
                      FOR pos = 0 THEN pos + 1 WHILE pos < strlen( word )
                      NEXT chars = COND #(
                        "if current character does not exist in character table,...
                        WHEN NOT line_exists( chars[ table_line = word+pos(1) ] )
                        "...then insert current character
                        THEN VALUE #( BASE chars ( word+pos(1) ) )
                        " otherwise keep current character table as it is
                        ELSE chars ) ) ) }| ) )  ) .

  ENDMETHOD.
ENDCLASS.

CLASS test IMPLEMENTATION.
  METHOD setup.
    cut = NEW #( ).
  ENDMETHOD.

  METHOD abap_is_excellent.

    cl_abap_unit_assert=>assert_equals(
        act = cut->solve( `ABАP  is excellent ` )
        exp = VALUE string_table(
           ( `Number of words: 3` )
           ( `Number of unique characters in the word: ABАP - 4` )
           ( `Number of unique characters in the word: is - 2` )
           ( `Number of unique characters in the word: excellent - 6` ) ) ).

  ENDMETHOD.

  METHOD lorem_ipsum_dolor_sit_amet .

    cl_abap_unit_assert=>assert_equals(
        act = cut->solve( `Lorem ipsum dolor sit amet` )
        exp = VALUE string_table(
           ( `Number of words: 5` )
           ( `Number of unique characters in the word: Lorem - 5` )
           ( `Number of unique characters in the word: ipsum - 5` )
           ( `Number of unique characters in the word: dolor - 4` )
           ( `Number of unique characters in the word: sit - 3` )
           ( `Number of unique characters in the word: amet - 4` )
            ) ).

  ENDMETHOD.

  METHOD many_trailing_spaces.
    cl_abap_unit_assert=>assert_equals(
        act = cut->solve( `start             ` )
        exp = VALUE string_table(
           ( `Number of words: 1` )
           ( `Number of unique characters in the word: start - 4` )
            ) ).
  ENDMETHOD.

  METHOD many_leading_spaces.
    cl_abap_unit_assert=>assert_equals(
        act = cut->solve( `             end` )
        exp = VALUE string_table(
           ( `Number of words: 1` )
           ( `Number of unique characters in the word: end - 3` )
            ) ).
  ENDMETHOD.

  METHOD many_space_in_the_middle.
    cl_abap_unit_assert=>assert_equals(
        act = cut->solve( `start          end` )
        exp = VALUE string_table(
           ( `Number of words: 2` )
           ( `Number of unique characters in the word: start - 4` )
           ( `Number of unique characters in the word: end - 3` )
            ) ).
  ENDMETHOD.

  METHOD complex.
    cl_abap_unit_assert=>assert_equals(
        act = cut->solve( `    one   two      thréé  ÄÖÜ  •••   ` )
        exp = VALUE string_table(
           ( `Number of words: 5` )
           ( `Number of unique characters in the word: one - 3` )
           ( `Number of unique characters in the word: two - 3` )
           ( `Number of unique characters in the word: thréé - 4` )
           ( `Number of unique characters in the word: ÄÖÜ - 3` )
           ( `Number of unique characters in the word: ••• - 1` )
            ) ).
  ENDMETHOD.

ENDCLASS.

START-OF-SELECTION.
  cl_demo_output=>display_data( NEW scccs( )->solve( p_text ) ).

To make it look more professional, I added some unit tests. 😉

I tried to explain each single statement inline as good as I was able to.

Although I used unit tests, clean code and only one line, I didn’t make it to the finals. 🙁

Maybe next time…

P.S.: Unfortunately I forgot to release this blog post… 🙁

P.S.S.: here is the Current Community Coding Challenge

That also reminds me to complete the Advent Of Code 2019

Assigned tags

      20 Comments
      You must be Logged on to comment or reply to a post.
      Author's profile photo Thomas Jung
      Thomas Jung

      Better late than never.  I loved the fact that you added so much explanation into the code sample.  Great for others to learn from.

      Author's profile photo Enno Wulff
      Enno Wulff
      Blog Post Author

      Thanks Thomas Jung for your positive feedback!

      Better late than never.

      That also were my thoughts. 🙂

       

      Author's profile photo Michelle Crapo
      Michelle Crapo

      I'm glad to see this one.   So yes - nice post, amazing code.

      And if I ever had to change anything in it,  I would go a little crazy.  OK, I'm already crazy.  I'd be a lot crazier.   😉

       

      Author's profile photo Enno Wulff
      Enno Wulff
      Blog Post Author

      Thanks Michelle Crapo !

      And if I ever had to change anything in it,  I would go a little crazy.

      That's why this kind of code will never do it to productive environment... 😉

      Author's profile photo Łukasz Pęgiel
      Łukasz Pęgiel

      Michelle Crapo think about Enno Wulff , how he needs to be crazy to create such code! 😀

      Author's profile photo Michelle Crapo
      Michelle Crapo

      Now that comment made me laugh this morning.  Yes, he must be crazy.  I think that is a prerequisite all technical people are a bit crazy.   Ummm...  That means you too.  🙂

      Author's profile photo Łukasz Pęgiel
      Łukasz Pęgiel

      Haha, yes I know 🙂 But if we're all crazy, shouldn't that became new normal? 😀

      Author's profile photo Mahesh Kumar Palavalli
      Mahesh Kumar Palavalli

      Cool Solution Enno Wulff  !!, I also used the count space hack to find total no of words. But I didn’t use regex or reduce and it came in one line ?

      I sent almost 5 emails to SAP ? with 5 solutions and in my first solution, I used classes(cl_abap_regex) as I was not aware about the usage of regex in string processing statements at that time. I did that also in a single line ? ? , although it looks ugly.

      But I really loved the learning journey from the 1st solution to the final solution. Maybe I will also write a blog post about it soon ?

      Author's profile photo Enno Wulff
      Enno Wulff
      Blog Post Author

      yeah, Mahesh Kumar Palavalli the learning curve is, what makes fun at least. 😀

      Author's profile photo Michael Keller
      Michael Keller

      If the "ABAP statement hero" badge does not yet exist, I suggest this badge. The first community member that she should get it should be Enno Wulff. Congratulations! 🙂

      Author's profile photo Enno Wulff
      Enno Wulff
      Blog Post Author

      ? well, I also know some others... 😉

      Author's profile photo helge dopler
      helge dopler

      oved the way that you included hair guide acnl such a great amount of clarification into the code test. Well done brother. 

      Author's profile photo Enno Wulff
      Enno Wulff
      Blog Post Author

      Thanks helge dopler !

      Author's profile photo Shai Sinai
      Shai Sinai

      Impressive.

      I guess this would be the most extreme interpretation for "one line of code".

      Author's profile photo Enno Wulff
      Enno Wulff
      Blog Post Author

      haha, yes. And most horrifying... 😀

      Author's profile photo Matthew Billingham
      Matthew Billingham

      That's what I was thinking. Write once, read never (well, not that bad!).

      Maybe we should have an ABAP Code Obfuscation Challenge https://www.ioccc.org/

       

       

       

      Author's profile photo Paul Hardy
      Paul Hardy

      Its a wonderful solution and also a demonstration of how the new ABAP syntax can make code utterly impossible to understand, which is why you had to comment most lines...

      Author's profile photo Enno Wulff
      Enno Wulff
      Blog Post Author

      I really took pains for creating this unreadable “solution”, Paul Hardy 😀

      Author's profile photo Łukasz Pęgiel
      Łukasz Pęgiel

      I love and hate the solution at the same time 🙂

      Would not like to see this in production but I prefer such style than the old-style code building fieldcatalog for ALV in 2000 lines.

      At the end you may refactor this to some additional methods and then no comments are needed.

      Author's profile photo Enno Wulff
      Enno Wulff
      Blog Post Author

      Hey Łukasz Pęgiel refactoring and splitting into dedicated methods would be the goal to achieve.