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: 
RichHeilman
Developer Advocate
Developer Advocate
We had a lot of fun doing the very first SAP Community Coding Challenge with all of you. I think we all learned a lot from each other which is what its all about.  We had about 200 submissions and it was really tough to narrow down the finalist which we announced earlier today.  Vote for your favorite here!  We wanted to take a moment and recognize some of the submissions that we think deserve special awards. Remember this is all in good fun, so don’t take offense.  ?

Brain Pain Award


Submitted by mobui

Yes, we call this one the Brain Pain Award, because when Tom and I read through it, our brains were in pain.  This example used one line of code for the solution leveraging several in-lined ABAP statements including REDUCE, FOR loops, and conditional statements.  I think we are very much impressed that someone actually wrote this code and understands how it is working. Impressive Sergey!
METHOD if_oo_adt_classrun~main.
out->write( |Brain Pain| ).
out->write( |https://people.sap.com/mobui| ).
out->write( |Сергей Чеботарев - Sergey Chebotarev| ).
DATA(sentence) = `ABАP is excellent `.

out->write( REDUCE string_table( INIT
full_result TYPE string_table
result TYPE string_table
word_count = 0
cur_word = ``
cur_word_uniq_len = 0
FOR i = 1 THEN i + 1 WHILE i LE strlen( sentence )
LET
i_cur_offset = i - 1
i_prev_offset = i - 2
char_cur = CONV char1( sentence+i_cur_offset(1) )
char_prew = COND char1( WHEN i_prev_offset GE 0 THEN sentence+i_prev_offset(1) ELSE space )
is_end_of_string = COND #( WHEN i EQ strlen( sentence ) THEN abap_true ELSE abap_false )
is_begin_of_word = COND #( WHEN char_cur NE space AND char_prew EQ space THEN abap_true ELSE abap_false )
is_end_of_word = COND #( WHEN char_cur EQ space AND char_prew NE space OR is_end_of_string EQ abap_true THEN abap_true ELSE abap_false )
IN NEXT
word_count = word_count + COND #( WHEN is_begin_of_word EQ abap_true THEN 1 ELSE 0 )
cur_word_uniq_len = COND #( WHEN is_begin_of_word EQ abap_true THEN 1 ELSE cur_word_uniq_len + COND #( WHEN char_cur NE space AND NOT ( cur_word CA char_cur ) THEN 1 ELSE 0 ) )
cur_word = COND #( WHEN is_begin_of_word EQ abap_true THEN char_cur ELSE COND #( WHEN char_cur NE space THEN cur_word && char_cur ELSE cur_word ) )
result = COND #( WHEN is_end_of_word EQ abap_true THEN CORRESPONDING #( BASE ( result ) VALUE string_table( ( | Number of unique characters in the word: { cur_word } - { cur_word_uniq_len } | ) ) )
ELSE result )
full_result = COND #( WHEN is_end_of_string EQ abap_true THEN CORRESPONDING #( BASE ( VALUE #( ( | Number of words: { word_count }| ) ) ) result ) ELSE full_result )
) ).

ENDMETHOD.


Kobayashi Maru Award


Submitted by 6b8e090ba50d45ec894fcae83b2f8a4a

This submission comes to us from our good friend Matt Harding.  Of course, his solution was to simply break the rules of the challenge and go his own way with code that is not actually implemented.  Well done Matt. ?
  METHOD if_oo_adt_classrun~main.
out->write( |Changed the Rules| ).
out->write( |https://people.sap.com/6b8e090ba50d45ec894fcae83b2f8a4a| ).
out->write( |Matt Harding| ).
DATA(sentence) = `ABАP is excellent `.

out->write(`The number of words in the provided sentence is: ` & count_words(sentence)).
LOOP AT split_sentence_into_words(sentence) reference into DATA(word_reference).
out->write(`The number of unique characters in the word ` & word_reference->* & ` is: ` & count_chars_in_word(word_reference->*).
ENDLOOP.

ENDMETHOD.


Crazy Binary Approach Award


Submitted by karsten.bohlmann

Here Karsten is doing a one liner REDUCE statement with bit-wise operators which was the only submission using bit-wise operators. Bit wise operation is something that most ABAPers never even mess around with. This is an impressive attempt at low level processing.
METHOD if_oo_adt_classrun~main.
out->write( |Binary Approach| ).
out->write( |https://people.sap.com/karsten.bohlmann| ).
out->write( |Karsten Bohlmann| ).
DATA(sentence) = `ABАP is excellent `.

out->write( REDUCE string(
LET words = condense( sentence ) " beware: might be empty
s = COND #( WHEN words <> `` THEN words && ` ` ) " add trailing space
zero = CONV xstring( `00` ) " needed later
IN
INIT text = |Number of words: { count_any_of( val = s sub = ` ` ) }|
k = 0 " offset of 1st word
FOR i = find_any_of( val = s sub = ` ` ) " end of 1st word
THEN find_any_of( val = s sub = ` ` off = i + 1 ) " end of next word
WHILE i > 0
NEXT text = CONV #(
LET wlen = i - k " length of current word
word = substring( val = s off = k len = wlen )
bits = REDUCE xstring( " (bit-)set of all codepoints in word
INIT x = VALUE #( )
FOR j = 0 UNTIL j >= wlen
NEXT x = x BIT-OR bit-set( cl_abap_conv_out_ce=>uccpi(
substring( val = word off = j len = 1 ) ) ) )
blen = xstrlen( bits ) * 8 " max. index of a '1' bit
bcnt = REDUCE i( " count '1' bits in xstring (= size of set)
INIT b = 0
FOR j = 0 UNTIL j > blen
NEXT b = b + COND #( WHEN bits BIT-AND bit-set( j ) <> zero THEN 1 ) )
IN |{ text }\nNumber of unique characters in the word: | &
|{ word } - { bcnt }| ) " [{ bits }]| )
k = i + 1 " offset of next word
)
).
ENDMETHOD.


Now Go Take a Shower Award


Submitted by 7a519509aed84a2c9e6f627841825b5a

While Morten did provide a solution in ABAP, he also sent us a solution for Java as well.  And of course after reading through it, we wanted to go shower off and for this reason we present the “Now Go Take a Shower Award” to Morten Wittrock.
 String sentence = "ABАP  is excellent ";
String[] words = sentence.split("\\s+");
System.out.printf("Number of words: %d%n", words.length);
for (String word : words) {
System.out.printf("Number of unique characters in the word: %s: %d%n", word, word.chars().distinct().count());
}


Kitchen Sink Award


Submitted by andreas.bork

We liked this submission because it had a little bit of everything in it, REDUCE, FOR loop, SWITCH statements, and RegEx.  This solution shows a good working knowledge of the statements used and how they can be used together. Good work Andreas!
  METHOD if_oo_adt_classrun~main.
out->write( |Kitchen Sink| ).
out->write( |https://people.sap.com/andreas.bork| ).
out->write( |Andreas Bork| ).
DATA(sentence) = `ABАP is excellent `.

out->write( VALUE string_table( FOR i = 0 UNTIL i = 4 LET lv_text = SWITCH string( i WHEN 0 THEN TEXT-001 ELSE |{ TEXT-002 }| )
lv_match = SWITCH string( i WHEN 0 THEN '' ELSE match( val = sentence regex = '\w+' occ = i ) )
lv_count = count( val = sentence regex = '\w+' )
lv_length = SWITCH i( i WHEN 0 THEN 0
ELSE strlen( REDUCE string( INIT lv_letter = `` FOR j = 0 THEN j + 1 UNTIL j > strlen( lv_match ) - 1
NEXT lv_letter = lv_letter && COND #( WHEN find( val = lv_letter sub = lv_match+j(1) ) < 0
THEN lv_match+j(1) ELSE '' ) ) ) )
IN ( |{ lv_text } { SWITCH string( i WHEN 0 THEN lv_count ELSE |{ lv_match } - { lv_length }| ) } | ) )
).
ENDMETHOD.


Teacher’s Pet Award


Submitted by jorge.sanchoroyo2

We wanted to give a special award for the submission which came close to the same solution that Tom and I came up with.  This code is pretty close, the FOR loop is a little different, and we actually in-lined the CONDENSE in the SPLIT statement to collapse those two lines into one line.  Congrats Jorge for being the Teacher’s Pet. ?
  METHOD if_oo_adt_classrun~main.
out->write( |Teachers Pet| ).
out->write( |https://people.sap.com/jorge.sanchoroyo2| ).
out->write( |Jorge Sancho| ).
DATA(sentence) = `ABАP is excellent `.

DATA lt_characters TYPE SORTED TABLE OF string WITH NON-UNIQUE KEY table_line.
CONDENSE sentence.
SPLIT sentence AT space INTO TABLE DATA(lt_words).
out->write( |Number of words { lines( lt_words ) }| ).
LOOP AT lt_words INTO DATA(ld_word).
lt_characters = VALUE #( FOR j = 0 WHILE ( j <= strlen( ld_word ) - 1 ) ( ld_word+j(1) ) ).
DELETE ADJACENT DUPLICATES FROM lt_characters.
out->write( |Number of unique characteres in the word: { ld_word } - { lines( lt_characters ) }| ).
ENDLOOP.
ENDMETHOD.


Test Class Award


Submitted by james.bungay3

Out of 200 or so submissions, there were only 3 or 4 that included test classes in their solution. So we thought we should highlight the submission with the most robust test classes here.  Nice work James!
interface YIF_WORD
public .
methods get_text
returning value(word_text) type string.
methods get_numberof_unique_characters
returning value(numberof_unique_characters) type i.
endinterface.


interface YIF_SENTENCE
public.
methods get_text
returning value(sentence_text) type string.
methods get_number_of_words
returning value(number_of_words) type i.
methods get_word
importing index type i
returning value(word) type ref to yif_word.
endinterface.


CLASS ycl_word DEFINITION

PUBLIC
FINAL
CREATE PUBLIC .

PUBLIC SECTION.
interfaces yif_word.
aliases get_numberof_unique_characters for yif_word~get_numberof_unique_characters.
aliases get_text for yif_word~get_text.
methods constructor
importing text_input type string.

PROTECTED SECTION.
PRIVATE SECTION.
data text type string.
data unique_character_count type i.
methods count_unique_characters.
ENDCLASS.

CLASS ycl_word IMPLEMENTATION.
METHOD constructor.
text = text_input.
count_unique_characters( ).
ENDMETHOD.
METHOD count_unique_characters.
unique_character_count = count( val = text regex = `(\S)(?!.*\1.*)` ).
ENDMETHOD.
METHOD yif_word~get_numberof_unique_characters.
numberof_unique_characters = unique_character_count.
ENDMETHOD.
METHOD yif_word~get_text.
word_text = text.
ENDMETHOD.
ENDCLASS.

class ltcl_word definition final for testing

duration short
risk level harmless.
private section.

methods return_word for testing.
methods empty_word for testing.
methods all_letters for testing.
methods all_numbers for testing.
methods all_symbols for testing.
methods mixed_characters for testing.
methods mixed_case for testing.
methods repeating_letters for testing.
methods repeating_letters_mixed_case for testing.
methods repeating_numbers for testing.
methods repeating_symbols for testing.
endclass.

class ltcl_word implementation.

method return_word.
data(cut) = new ycl_word( `testing` ).
cl_abap_unit_assert=>assert_equals( act = cut->get_text( ) exp = `testing` ).
endmethod.
method all_letters.
data(cut) = new ycl_word( `testing` ).
cl_abap_unit_assert=>assert_equals( act = cut->get_numberof_unique_characters( ) exp = 6 ).
endmethod.
method all_numbers.
data(cut) = new ycl_word( `1234567` ).
cl_abap_unit_assert=>assert_equals( act = cut->get_numberof_unique_characters( ) exp = 7 ).
endmethod.
method all_symbols.
data(cut) = new ycl_word( `!@#$%^)` ).
cl_abap_unit_assert=>assert_equals( act = cut->get_numberof_unique_characters( ) exp = 7 ).
endmethod.
method empty_word.
data(cut) = new ycl_word( `` ).
cl_abap_unit_assert=>assert_equals( act = cut->get_numberof_unique_characters( ) exp = 0 ).
endmethod.
method mixed_characters.
data(cut) = new ycl_word( `we!c0me` ).
cl_abap_unit_assert=>assert_equals( act = cut->get_numberof_unique_characters( ) exp = 6 ).
endmethod.
method mixed_case.
data(cut) = new ycl_word( `TestS` ).
cl_abap_unit_assert=>assert_equals( act = cut->get_numberof_unique_characters( ) exp = 5 ).
endmethod.
method repeating_letters.
data(cut) = new ycl_word( `bananas` ).
cl_abap_unit_assert=>assert_equals( act = cut->get_numberof_unique_characters( ) exp = 4 ).
endmethod.
method repeating_letters_mixed_case.
data(cut) = new ycl_word( `BaNAnaS` ).
cl_abap_unit_assert=>assert_equals( act = cut->get_numberof_unique_characters( ) exp = 6 ).
endmethod.
method repeating_numbers.
data(cut) = new ycl_word( `111222` ).
cl_abap_unit_assert=>assert_equals( act = cut->get_numberof_unique_characters( ) exp = 2 ).
endmethod.
method repeating_symbols.
data(cut) = new ycl_word( `Help!!!!!` ).
cl_abap_unit_assert=>assert_equals( act = cut->get_numberof_unique_characters( ) exp = 5 ).
endmethod.
endclass.


CLASS ycl_sentence DEFINITION

PUBLIC
FINAL
CREATE PUBLIC .

PUBLIC SECTION.
interfaces yif_sentence.
aliases get_number_of_words for yif_sentence~get_number_of_words.
aliases get_text for yif_sentence~get_text.
aliases get_word for yif_sentence~get_word.
methods constructor
importing text_input type string.

PROTECTED SECTION.
PRIVATE SECTION.
data text type string.
data word_count type i.
methods count_words.
ENDCLASS.



CLASS ycl_sentence IMPLEMENTATION.
METHOD constructor.
text = text_input.
count_words( ).
ENDMETHOD.

METHOD count_words.
word_count = count( val = condense( text ) regex = `(\b[^\s]+\b)` ).
ENDMETHOD.

METHOD yif_sentence~get_number_of_words.
number_of_words = word_count.
ENDMETHOD.

METHOD yif_sentence~get_text.
sentence_text = text.
ENDMETHOD.

METHOD yif_sentence~get_word.
word = new ycl_word( cond #( when index between 1 and word_count then segment( val = text index = index space = ` ` ) else `` ) ).
ENDMETHOD.
ENDCLASS.



class ltcl_sentence definition final for testing
duration short
risk level harmless.

private section.
methods return_sentence for testing.
methods return_word for testing.
methods index_out_of_bounds for testing.
methods one_word for testing.
methods no_words for testing.
methods multiple_words for testing.
methods multiple_spaces for testing.

endclass.

class ltcl_sentence implementation.
method return_sentence.
data(cut) = new ycl_sentence( `Hello World` ).
cl_abap_unit_assert=>assert_equals( act = cut->get_text( ) exp = `Hello World` ).
endmethod.
method multiple_spaces.
data(cut) = new ycl_sentence( `Hello World ` ).
cl_abap_unit_assert=>assert_equals( act = cut->get_number_of_words( ) exp = 2 ).
endmethod.
method multiple_words.
data(cut) = new ycl_sentence( `Hello World and Hello again World` ).
cl_abap_unit_assert=>assert_equals( act = cut->get_number_of_words( ) exp = 6 ).
endmethod.
method no_words.
data(cut) = new ycl_sentence( `` ).
cl_abap_unit_assert=>assert_equals( act = cut->get_number_of_words( ) exp = 0 ).
endmethod.
method one_word.
data(cut) = new ycl_sentence( `Hello` ).
cl_abap_unit_assert=>assert_equals( act = cut->get_number_of_words( ) exp = 1 ).
endmethod.
method index_out_of_bounds.
data(cut) = new ycl_sentence( `Hello World` ).
cl_abap_unit_assert=>assert_equals( act = cut->get_word( 3 )->get_text( ) exp = `` ).
endmethod.
method return_word.
data(cut) = new ycl_sentence( `Hello World` ).
cl_abap_unit_assert=>assert_equals( act = cut->get_word( 2 )->get_text( ) exp = `World` ).
endmethod.
endclass.


CLASS ycl_sap_cc_20200228_clean DEFINITION
PUBLIC
FINAL
CREATE PUBLIC .

PUBLIC SECTION.
interfaces if_oo_adt_classrun.

PROTECTED SECTION.
PRIVATE SECTION.
types word_element type ref to yif_word.
ENDCLASS.

CLASS ycl_sap_cc_20200228_clean IMPLEMENTATION.
METHOD if_oo_adt_classrun~main.
DATA(sentence) = new ycl_sentence( `ABАP is excellent ` ).
out->write( reduce stringtab(
init output = value #( ( |Number of words: { conv string( sentence->get_number_of_words( ) ) }| ) )
word type word_element
for index = 1 until index > sentence->get_number_of_words( )
next word = sentence->get_word( index )
output = value #( BASE output ( |Number of unique characters in the word: { word->get_text( ) } - { conv string( word->get_numberof_unique_characters( ) ) }| ) ) ) ).

ENDMETHOD.

ENDCLASS.


Again congratulations to the finalist as well as to the special award winners.  Great job ABAPers! Remember to vote for your favorite here and stay tuned for the next challenges in the coming months.
16 Comments