Application Development Blog Posts
Learn and share on deeper, cross technology development topics such as integration and connectivity, automation, cloud extensibility, developing at scale, and security.
cancel
Showing results for 
Search instead for 
Did you mean: 
ennowulff
Active Contributor
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 pjl and 28f4b37a40894f18a22abc696b8154f4 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...
20 Comments