This sounds very much like the Luhn test task at RosettaCode. https://rosettacode.org/wiki/Luhn_test_of_credit_card_numbers except that there it is described as working on the digits of an integer.
(1) There are two approaches to traversing a sequence in reverse. (A) Reverse the sequence, then traverse the copy forward. aString reverse do: [:each | ...] (B) Just traverse the sequence in reverse aString reverseDo: [:each | ...] My taste is for the second. (2) There are two approaches to deleting spaces. (A) Make a copy of the string without spaces. x := aString reject: [:each | each = Character space]. x do: ... (B) Ignore spaces as you go: (i) aString do: [:each | each = Character space ifFalse: [...]] (ii) aString select: [:each | each ~= Character space] thenDo: [:each | ...] Combining (1A) and (2A) you get very obvious code: (aString reject: [:each | each = Character space]) reverse do: [:digit } ...] Combining (1B) and (2Bi) you get more efficient code: aString reverseDo: [:digit | digit = Character space ifFalse: [ ...]] By the way, let's start by checking that the character in the string *are* digits or spaces: (aString allSatisfy: [:each | each isDigit or: [each = Character s[ace]]) ifFalse: [^false], (3) There are two approaches to doubling the even digits. (A) Make a new string that starts as a copy and change every second digit from the right. (B) Simply *act* as if this has been done; keep track of whether the current digit position is even or odd and multiply by 1 or 2 as appropriate. nextIsOdd := true. aString reverseDo: [:digit | digit = Character space ifFalse: [ nextIsOdd ifTrue: [oddSum := ...] ifFalse: [evenSum := ...]. nextIsOdd := nextIsOdd not]]. I *like* code that traverses a data structure exactly once and allocates no intermediate garbage, so I'd be making (B) choices. But I am not at all sure that it is right for *you* at this stage. Your goal is to get practice in making code that is obviously correct and lends itself to testing. I think in your case it makes more sense to make the (A) choices. You can write some code that reverses a string (using the built-in method) and test that it does what you expect. You can write some code that checks whether a string contains only digits and spaces, and test that. You can write some code that returns a space-less copy, and test that. You can write some code that returns the even (odd) elements of a sequence, and test those. SequenceableCollection>> withIndexSelect: aBlock |index| index := 0. ^self select: [:each | aBlock value: each value: (index := index + 1)] evenElements ^self withIndexSelect: [:each :index | index even] oddElements ^self withIndexSelect: [:each :index | index odd] The easiest way to convert a string to numbers and add up the numbers is to use #detectSum, as in aString oddElements detectSum: [:char | char digitValue] How do you find #digitValue? By looking in Character. #detectSum:? Collection enumeration methods. Using the (A) approach will give you lots of little methods, which you can comment and above all TEST, so that each mistake will be in just one small method. This is a typical functional programming "lots of little functions" approach. On Thu, 30 Apr 2020 at 18:33, Roelof Wobben via Pharo-users <pharo-users@lists.pharo.org> wrote: > > Hello, > > I hope I can discuss my approch to this problem : > > Given a number determine whether or not it is valid per the Luhn formula. > > The Luhn algorithm is a simple checksum formula used to validate a variety of > identification numbers, such as credit card numbers and Canadian Social > Insurance Numbers. > > The task is to check if a given string is valid. > > Validating a Number > > Strings of length 1 or less are not valid. Spaces are allowed in the input, > but they should be stripped before checking. All other non-digit characters > are disallowed. > > Example 1: valid credit card number > > 4539 1488 0343 6467 > > The first step of the Luhn algorithm is to double every second digit, > starting from the right. We will be doubling > > 4_3_ 1_8_ 0_4_ 6_6_ > > If doubling the number results in a number greater than 9 then subtract 9 > from the product. The results of our doubling: > > 8569 2478 0383 3437 > > Then sum all of the digits: > > 8+5+6+9+2+4+7+8+0+3+8+3+3+4+3+7 = 80 > > If the sum is evenly divisible by 10, then the number is valid. This number > is valid! > > > my idea was to do these steps > > 1) reverse the input. > > 2) use this to double every second digit and calculate the sum of all the > numbers : > > checkNumber := (collection reverse selectwith index: [:item :index | (index > % 2 == 0) . IfTrue: [item *2]] ) sumNumbers > > 3) check if its a valid number by doing this : > > > ^ (checkNumber % 10 == 0) > > > is this a good game plan or has it flaws or can I do it better ? > > Regards, > > > Roelof > >