On Sun, 3 May 2020 at 03:09, Roelof Wobben <r.wob...@home.nl> wrote:

> Op 2-5-2020 om 19:33 schreef Ben Coman:
>
>
>
> On Sat, 2 May 2020 at 15:52, Roelof Wobben via Pharo-users <
> pharo-users@lists.pharo.org> wrote:
>
>> Op 1-5-2020 om 08:35 schreef Roelof Wobben:
>> >> On Fri, 1 May 2020 at 02:16, Roelof Wobben <r.wob...@home.nl> wrote:
>> >>> Op 30-4-2020 om 16:06 schreef Richard O'Keefe:
>> >>>> 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.
>> >>>>
>> >>>>
>> >>> For me  , I use this to practice solving problems  and doing the
>> >>> "right"
>> >>> steps.
>> >>> So I love it , that so many people share there way of solving it.
>> >>> I can learn a lot from it
>> >>> Expecially when they explain there thinking process so detailed.
>> >>>
>> >>> I like this code also a lot.
>> >>> Am  I correct for testing if it is a valid string by doing this ^
>> >>> (oddSum + evenSum) dividedBy: 10
>> >>>
>> >>> Roelof
>> >>>
>> >
>> >
>> > oke,
>> >
>> > so this is better
>> >
>> > cardNumber := '8273 1232 7352 0569'.
>> > oddSum := 0.
>> > evenSum := 0.
>> > nextIsOdd := false.
>> >      cardNumber reverseDo: [:character |
>> >           digit := character digitValue.
>> >          character = Character space ifFalse: [
>> >          nextIsOdd
>> >              ifFalse:  [oddSum := oddSum + digit ]
>> >              ifTrue: [(digit >= 5 )
>> >     ifTrue: [evenSum := evenSum + (digit * 2) - 9 ]
>> >     ifFalse: [ evenSum := evenSum + (digit * 2) ]].
>> >             nextIsOdd := nextIsOdd not]].
>> > ^ evenSum + oddSum // 10 == 0.
>> >
>> >
>> > where I could even make a seperate method of the ifTrue branch when
>> > the digit is greater then 5.
>> >
>> >
>> nobody who can say if this is a good solution ?
>>
>
> You didn't actually ask a question :)
>
> btw, Its good you are stretching yourself to do it the most complicated
> way,
> but pay attention that when Richard says HE "likes code that traverses a
> data structure exactly once"
> its because he is starting with the philosophy to OPTIMISE for EFFICIENCY.
> Often in programming that is the LAST thing you should do because to do so
> your code often becomes more complex,
> and Kernagan's law applies...
> https://talixa.com/blog/why-i-write-simple-code/
>
> In general, you want to avoid premature optimization.
> https://effectiviology.com/premature-optimization/
>
> The catch-phrase I see around this forum priorities things in this order:
> 1. Make it work.
> 2. Make it right.
> 3. Make it fast.
> and often you can stop at 2 because it is already "fast enough".
>
> Considering your code above, if I take TIME to go through it, I can
> evaluate that it seems right
> but I remain feeling that I could have missed something.
>
> Something like Richard's (A) examples without loops  I would consider to
> be "more good".
> since each line can be dealt with individually.
>
> cardNumber := '4539 1488 0343 6467'.
> cleanDigits := cardNumber copyWithout: Character space.
> preWrapDigits := cleanDigits asArray collectWithIndex: [ :char :idx |
> (idx\\2 + 1) * char digitValue ].
> wrappedDigits :=  preWrapDigits collect: [ :d | d > 9 ifFalse: [ d ]
> ifTrue: [ d-9 ] ].
> ^ wrappedDigits sum isDivisibleBy: 10.
>
> A side benefit is having full result of each transformation available to
> be reviewed,
> rather than having only pieces of it in view when you debug a loop.
>
> In the end though, yours is a good solution first and foremost because
> tried a more detailed way and you got it working!!
> Remember there is more than one "good way" to do it depending on what you
> are optimising for - efficiency or readability.
>
> cheers -ben
>
>
>
> I think I find readability more important then efficieny.
>
> But I think I have to alter your code. At first look it does not look like
> that every second value from the right is multiplied by 2.
>
> When the index is for example 7 .
>
> 7 // 2 gives  3.
> Maybe it needs to be %.
>

But why are you testing // when my code uses \\ ? :)
small details can have a big impact.

cheers -ben

Reply via email to