Reddit daily programmer problems

Oforth examples. Feel free to post your own code.

Reddit daily programmer problems

Postby sotolf » 09 Aug 2015 19:22

Garland words

The thought behind garland words are that they begin and end on the same letter sequence like onion, this little program is finding how many letters are like this in a given word.

Code: Select all
String method: fromBack(n)
{ self size 1 + n - }

String method: garlandFactor(n)
{
    n 1 self extractAndStrip
    self size self fromBack(n) self extractAndStrip
    ==
}

String method: findGarlandFactor
{
    self size 1 - seq
    filter(#[ self garlandFactor ])
    maxFor(#[])
    dup isNull ifTrue:[drop 0]
}

: pprint(inp) { inp ": " + print inp findGarlandFactor println }

["programmer", "ceramic", "onion", "alfalfa"] apply(#pprint)


Output:

Code: Select all
programmer: 0
ceramic: 1
onion: 2
alfalfa: 4


shuffeling a list

Code: Select all
: input { "a e i o u y" }

Collection method: randomIdx
{
    self size rand
}

Collection method: shuffle
{   | old new |
    self ->old
    [] ->new
    while(old isEmpty not)
    [ old randomIdx dup old at new + ->new
      dup old del ->old ]
    new
}

: pprint(list)
{
    list apply( #[ print " " print ] ) "" println
}

input words shuffle pprint


Shuffles a list randomly, here I see I use the same pretty print that franck was correcting earlier, so that is at least one point that is sub optimal in this snippet.
sotolf
 
Posts: 55
Joined: 30 Jul 2015 15:53

Re: Reddit daily programmer problems

Postby Franck » 10 Aug 2015 15:09

Hello,

Here are some suggestions on your (good) code :

1) #extractAndStrip purpose is to remove leading blanks.
Here #extract will suffice.

2) There is a method on Object class : #yourself, that returns the receiver.
Object method: yourself { self }

This seems to be a strange method (why would I need to just return the receiver ?), but it can be usefull. And here, it is a typical case where it is usefull :

Instead of writing : maxFor(#[]), you can just write : maxFor(#yourself)

Now the algorithm : I like functionnal programming, but here I think I
would just use a loop, using #step: to go from the max possible string to the min possible string.

I don't know if you already know #step:

Code: Select all
a b s step: x [ ... ] // Go from a to b using step s.


So #findGarlandFactor could be written like this :

Code: Select all
String method: findGarlandFactor   // ( s -- n )
{
| i |
   self size dup isOdd + 2 / 1 -1 step: i [
      self left(i) self right(i) == ifTrue: [ i return ]
      ]
   0
}



For shuffeling a list :

1) null can also be seen as an empty list, so, as local variables are initialized to null, "[ ] ->new" line is not required :

Code: Select all
>10 seq null + .s
[1] (List) [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
ok


2) "isEmpty not" exists as a method: #notEmpty

3) No very important, but your method won't work for all collections, just for indexable collections (#at(aInteger) is needed).
For instance, if you try your method on a hash, you will have an exception (Hash does not understand at).
==> #shuffle should be a method of Indexable proprety.

4) I have a rule : when I need to create a list by hand, I create a mutable list (a ListBuffer) and populate it.

I think that this is a case where immutability does not work very well and a mutable object works much better.
With ListBuffer (and StringBuffer), you can add objects to the list until it is complete :

For instance :

Code: Select all
Collection method: shuffle
{
| l |
   ListBuffer newSize(self size)
   self asListBuffer ->l
   while(l notEmpty) [ l removeAt(l size rand) over add ]
}


This is optimized because you create only 2 lists (the result and l).
Otherwise, if you do it with immutable lists (and you can do it, this not a problem, pure functional languages don't have mutable objects), #+ creates a list and #del creates a list, so 2n + 1 lists are needed to create the result.

Franck
Franck
 
Posts: 162
Joined: 29 Oct 2014 19:01

Re: Reddit daily programmer problems

Postby sotolf » 10 Aug 2015 17:19

Again, thank you for an insightful and nice post, I'm slowly building up some more knowledge now :)

1) #extractAndStrip purpose is to remove leading blanks.
Here #extract will suffice.


Yup, I need to reread the language page to catch up on functions, it seems like I'm choosing a suboptimal one pretty often.

Instead of writing : maxFor(#[]), you can just write : maxFor(#yourself)


That looks a lot cleaner.

So #findGarlandFactor could be written like this :


Yeah, that looks better, I was not thinking about step, but that way it doesn't have to check all of the possibilities first, it's cleaner like that. And forth is more or less functional no matter how one codes, because of the stack, so the functions for them self doesn't need to be functional, but how they work on the stack is more or less functional ;)

1) null can also be seen as an empty list, so, as local variables are initialized to null, "[ ] ->new" line is not required :


Ah, so nil punning works, I don't know why I didn't try that out, but now I know ;)

2) "isEmpty not" exists as a method: #notEmpty


another quality of life improvement for me, that means I'll have less problems reading my code later.

3) No very important, but your method won't work for all collections, just for indexable collections (#at(aInteger) is needed).
For instance, if you try your method on a hash, you will have an exception (Hash does not understand at).
==> #shuffle should be a method of Indexable proprety.


That's definately a good point, for that program it wouldn't hurt as you said, but if I was thinking "I wrote that already, I'll just paste it in" to another program I could bring myself in trouble, so I'd better fix that.

4) I have a rule : when I need to create a list by hand, I create a mutable list (a ListBuffer) and populate it.


Seems like a good rule, I've been programming haskell and clojure lately, so I tend to forget about the non-functional ways of doing those things. With that rule though, I have a way to remember to think about it :)
sotolf
 
Posts: 55
Joined: 30 Jul 2015 15:53


Return to Oforth examples

Who is online

Users browsing this forum: No registered users and 1 guest

cron