Author Archives: steven.proctor@gmail.com

Ruby Tuesday – Functional fizzbuzz

Today we are going to take a quick break from looking at some different library methods for today’s Ruby Tuesday post.

Last Friday I was going back and forth with a teammate over our chat tool about some different programming problems we could use to do some very basic screening of candidates, and I mentioned that if nothing else there is always fizzbuzz.

fizzbuzz, for anybody who at this point has yet to encounter it, even by just blog posts such as this, take a number N, and prints out fizz if the number is a multiple of three, buzz if the number is a multiple of 5, fizzbuzz if the number is both a multiple of three and five, or else just the number itself if none of the conditions hold true.

While fizzbuzz, isn’t a great problem, and, depending on the circles you are in, can be pretty worthless because most candidates have seen it already, it can still have its place. But, sadly, there are developer candidates we encounter that have a hard time translating the problem above, which states the algorithm in English, directly into code. The reason I think fizzbuzz can be interesting, as I mentioned to my coworker, is it can give candidates a chance to show off some more advanced topics that they wish to show off, if they wish.

After mentioning that benefit to him on Friday, I came across the post “Bro, Do You Even FizzBuzz?!?” on fizzbuzz in Clojure and shows off a solution of not using the modulus operator to determine the result.

I decided I would attempt to translate the solution to Ruby, to prove out the point of our conversation.

def do_fizzbuzz(n)
  fizz = ['', '', 'fizz'].cycle.lazy
  buzz = ['', '', '', '', 'buzz'].cycle.lazy
  fizzbuzz = fizz.zip(buzz).map(&:join)
  puts (1..n).
         zip(fizzbuzz).
         map {|number, translation| if translation.empty? then number else translation end}.
         join("n")
end

First, we declare the “fizzes” as a lazy repeating array of blank strings, where every third is the string ‘fizz’, by using cycle and lazy. We do the same for the occurrences of buzz, but have it be every fifth item in an array.

We then zip the fizz and buzz lazy enumerations together, and then map over that result joining the two strings together, e.g. ["", ""].join, ["fizz", ""].join, ["", "buzz"].join, or ["fizz", "buzz"].join.

After we have our lazy enumeration of fizzbuzz translations, we take the range of numbers from 1 to N, zip that together with the translations, pick the translation if it is not an empty string, otherwise pick the number, and then join all of the results together with a newline separator, so each entry will print on its own line.

There you have it, a functional programming style fizzbuzz solution that does not use the modulus operator to arrive at a solution.

–Proctor

Erlang Thursday – c:xm/1

Today’s Erlang Thursday takes a turn down a slightly different route and takes a look in the c module at c:xm/1.

c:xm/1 takes either a atom, representing the name of a module, or a string, representing a filename, and inspects that module for unused and undefined functions, as well as calls to deprecated functions.

First let’s take a look at the erlang module, and see if there is anything in there that is deprecated.

c:xm(erlang).
% [{deprecated,[]},{undefined,[]},{unused,[]}]

Looks like there are no calls to deprecated functions, no calls to undefined functions, and no unused functions floating around in the erlang module. Note: This is running under Erlang 17.3.4, and you may get a different result depending on the version of Erlang you are running, because erlang:now/0 has been deprecated as of v18.0.

Trying to come up with an example of an existing module that might have some of these criteria, I took a look at the README for Erlang 17.0, and did a search for deprecated. Doing that there was a note:

The module pg has been deprecated and will be removed in Erlang/OTP 18.

So let’s pass that module to c:xm/1 and see what we get.

c:xm(pg).
% [{deprecated,[{{pg,create,1},{pg,master,1}},
%               {{pg,create,2},{pg,master,1}}]},
%  {undefined,[]},
%  {unused,[]}]

And we can see that we do get information back about deprecated functions in the pg module.

While the odds are low that you will need to use this function in your normal day to day work, as the tooling around Erlang generally seems to take care of this for you, this was intriguing enough that it seemed worthy of calling it out, especially if for those time when the compilation of Erlang code is done from inside the Erlang shell.

–Proctor

Ruby Tuesday – String#squeeze

Today’s Ruby Tuesday is on String#squeeze.

String#squeeze replaces runs of repeated characters in a source string down to a single character in the returned string.

"foo".squeeze
# => "fo"
"bar".squeeze
# => "bar"
"Mississippi".squeeze
# => "Misisipi"

String#squeeze can also take a string an argument. If a string is passed in, that string is seen as a set of characters to use for squeezing against the source string.

"Mississippi".squeeze("")
# => "Mississippi"
"Mississippi".squeeze("s")
# => "Misisippi"
"Mississippi".squeeze("abcprt")
# => "Mississipi"
"Mississippi".squeeze("sp")
# => "Misisipi"

If a string contains a - between two characters, that string is seen as containing a sequence of characters to include in the set of chacters to match for squeezing against the source string, but if it is first or last the - is seen as a character by itself.

"Mississippi".squeeze("a-r")
# => "Mississipi"
"Mississippi".squeeze("q-z")
# => "Misisippi"
"Mississippi".squeeze("pr-t")
# => "Misisipi"
"^^--~".squeeze('-~^')
# => "^-~"

If a string starts with a ^ then that string is seen as the negation of the set of characters that were given in that string to use, but if it is not the first character, then it is just seen as a normal ^ character.

"Mississippi".squeeze("^a-r")
# => "Misisippi"
"^^--~".squeeze('-^')
=> "^-~"

Backslashes can also be used to escape characters from any special meaning, but when using the backslash character in a double quoted string, then you have to make sure to escape that backslash with another backslash for it to be treated as an escape character in the string to String#squeeze.

"^^--~".squeeze('^')
# => "^--~"
"^^--~".squeeze("\^")
# => "^--~"
"^^--~~".squeeze('~-^')
# => "^-~"

String#squeeze doesn’t modify the source string given, but returns a new instance of a string for the result. If you do need to modify the string in place for some reason, there exists a String#squeeze! as well, but like many other Ruby methods that end in a !, if the original item is not modified a nil is returned.

str = "Mississippi"
# => "Mississippi"
str.squeeze
# => "Misisipi"
str
# => "Mississippi"
str.squeeze!
# => "Misisipi"
str
# => "Misisipi"
"bar".squeeze!
# => nil
"foo".squeeze!
# => "fo"

–Proctor

Guest on Three Devs and a Maybe

I was recently asked to be on the podcast Three Devs and a Maybe, and am happy to announce that episode is now live.

I talked about my background of getting into computers, my route into functional programming, Clojure, Erlang, and a little bit off background on how I decided to start Functional Geekery.

Make sure to take a listen to Episode 71 – Erlang and Clojure with Steven Proctor and let me know what you think.

Thanks to Edd Mann and Michael Budd for the invite, and a great conversation.

–Proctor

Erlang Thursday – ordsets:is_subset/2

Today’s Erlang Thursday covers ordsets:is_subset/2.

ordsets:is_subset/2 takes two Ordered Sets, and checks if the ordered set passed in as the first argument is a subset of ordered set passed in as the argument. For a given set, Set A, to be a subset of another set, Set B, every item in Set A must also be a member of Set B.

SetA = ordsets:from_list(lists:seq(1, 10)).
% [1,2,3,4,5,6,7,8,9,10]
SetB = ordsets:from_list(lists:seq(2, 10, 2)).
% [2,4,6,8,10]
SetC = ordsets:from_list(lists:seq(1, 15, 3)).
% [1,4,7,10,13]
EmptySet = ordsets:new().
% []
ordsets:is_subset(SetB, SetA).
% true
ordsets:is_subset(SetA, SetB).
% false
ordsets:is_subset(SetC, SetA).
% false

And for those who aren’t as familiar with set theory, a few quick facts about sets. First, the empty set is a subset of all sets; second, a set is considered a sub-set of itself; and lastly, a given Set B is a superset of Set A, if Set A is subset of Set B.

ordsets:is_subset(EmptySet, SetA).
% true
ordsets:is_subset(EmptySet, SetB).
% true
ordsets:is_subset(EmptySet, SetC).
% true
ordsets:is_subset(EmptySet, EmptySet).
% true
ordsets:is_subset(SetA, SetA).
% true

–Proctor

Ruby Tuesday – Array#fetch

Today’s Ruby Tuesday covers a variation of one of my personal favorite set of Ruby methods, Array#fetch.

Array.fetch takes an integer for an argument and gets the element for a given index, using 0-based index scheme.

icao = [:alpha, :bravo, :charlie, :delta, :foxtrot]
# => [:alpha, :bravo, :charlie, :delta, :foxtrot]
icao.fetch 1
# => :bravo
icao.fetch 0
# => :alpha

It also can get you the elements walking backward from a list

icao.fetch -1
# => :foxtrot
icao.fetch -4
# => :bravo

If an index is out of bounds of the array, either positive of negative, an IndexError is raised.

icao.fetch 5
# IndexError: index 5 outside of array bounds: -5...5
# from (pry):5:in `fetch'
icao.fetch -7
# IndexError: index -7 outside of array bounds: -5...5
# from (pry):11:in `fetch'

At this point, I can hear you saying:

So what?! I can do this using a subscript to an array and not get exceptions but a nil when something is not found.
–You

icao[4]
# => :foxtrot
icao[0]
# => :alpha
icao[-1]
# => :foxtrot
icao[-7]
# => nil
icao[5]
# => nil

And you would be right.

But where you might run into trouble with just using a subscript index, is if you have nils in your array.

some_nils[2]
# => nil
some_nils[100]
# => nil

This is where Array#fetch makes its way to one of my favorite Ruby methods.

When you decide to use Array#fetch over just subscripts, you can specify a default value that you get back if the index is out of bounds.

icao.fetch 2, :fubar
# => :charlie
icao.fetch 5, :snafu
# => :snafu
icao.fetch -7, :fubar
# => :fubar

And to top it off, you can even pass a whole block which is called with the index passed to fetch, so you can do more detailed logic if needed.

icao.fetch(-7) { |index| "SNAFU occured trying to fetch with index #{index}" }
# => "SNAFU occured trying to fetch with index -7"

–Proctor

Erlang Thursday – ordsets:subtract/2

Today’s Erlang Thursday is on ordsets:subtract/2.

ordsets:subtract/2 takes two ordered sets as its arguments, and returns a ordered set containing the items of the first ordered set that are not in the second ordered set.

OrderedSetA = ordsets:from_list([5, 4, 3, 2, 1]).
# [1,2,3,4,5]
OrderedSetB = ordsets:from_list([1, 1, 2, 3, 5, 8, 13]).
# [1,2,3,5,8,13]
OrderedSetC = ordsets:from_list([2, -2, 4, -4, 16, -16]).
# [-16,-4,-2,2,4,16]
EmptySet = ordsets:new().
# []
ordsets:subtract(OrderedSetA, OrderedSetB).
# [4]
ordsets:subtract(OrderedSetA, EmptySet).
# [1,2,3,4,5]
ordsets:subtract(OrderedSetB, EmptySet).
# [1,2,3,5,8,13]
ordsets:subtract(EmptySet, OrderedSetA).
# []
ordsets:subtract(OrderedSetB, OrderedSetC).
# [1,3,5,8,13]

And note that ordsets:subtract/2 is not commutative, unlike ordsets:union/2 or ordsets:intersection/2.

ordsets:subtract(OrderedSetA, OrderedSetC).
# [1,3,5]
ordsets:subtract(OrderedSetC, OrderedSetA).
# [-16,-4,-2,16]

And again, your friendly reminder if you haven’t been following along, just because Ordered Sets in Erlang are represented as a List, doesn’t mean that Lists are Ordered Sets.

–Proctor

Ruby Tuesday – Array#sample

Today’s Ruby Tuesday is on Array#sample.

Array#sample has a couple of different forms it can take.

The first form it can take is a version where no arguments are passed; in this case it returns a random element from the array it was called on, or nil if the array is empty.

[1, 2, 3, 4, 5].sample
# => 4
[1, 2, 3, 4, 5].sample
# => 1
[1, 2, 3, 4, 5].sample
# => 2
[].sample
# => nil
[:heart, :diamond, :club, :spade].sample
# => :club

Array#sample can also take as its argument a count of the number of random items to be returned.

[1, 2, 3, 4, 5].sample 2
# => [1, 2]
[1, 2, 3, 4, 5].sample 2
# => [2, 1]
[1, 2, 3, 4, 5].sample 2
# => [1, 3]
[1, 2, 3, 4, 5].sample 2
# => [3, 5]
[1, 2, 3, 4, 5].sample 2
# => [5, 2]

If the argument to the count is greater than, or equal to, the number of items in the array, then the array is returned.

[:heart, :diamond, :club, :spade].sample 6
# => [:heart, :diamond, :spade, :club]

This has two subtle but important consequences. First if we call sample with a count on an empty array, an empty array is returned, instead of a nil like we would get back if we just call Array#sample with no count argument. This includes calling Array#sample with a count of zero on an empty array.

[].sample
# => nil
[].sample 0
# => []
[].sample 1
# => []
[].sample 3
# => []

Second, it shows that as we sample the array, we are not going to get duplicate elements, unless they were in the array to being with.

On both of these forms, a random number generator can also be passed. This can give us a repeatable generation sequence as we can prime the generator with a given seed.

generatorA = Random.new 1
# => #<Random:0x007f86c3925878>
(1..100).to_a.sample(random: generatorA)
# => 38
(1..100).to_a.sample(random: generatorA)
# => 13
(1..100).to_a.sample(random: generatorA)
# => 73
generatorB = Random.new 1
# => #<Random:0x007f86c497dd10>
(1..100).to_a.sample(random: generatorB)
# => 38
(1..100).to_a.sample(random: generatorB)
# => 13
(1..100).to_a.sample(random: generatorB)
# => 73
(1..100).to_a.sample(random: generatorB)
# => 10
(1..100).to_a.sample(random: generatorA)
# => 10

(1..100).to_a.sample(4, random: generatorA)
# => [76, 6, 82, 66]
(1..100).to_a.sample(4, random: generatorA)
# => [17, 2, 79, 74]
(1..100).to_a.sample(4, random: generatorB)
# => [76, 6, 82, 66]
(1..100).to_a.sample(4, random: generatorB)
# => [17, 2, 79, 74]

And if we want to pick a random card from a deck of cards, or even draw a 5 card hand we can use Array#sample on an array of “playing cards”.

suit = [:heart, :diamond, :club, :spade]
# => [:heart, :diamond, :club, :spade]
rank = [:ace, 2, 3, 4, 5, 6, 7, 8, 9, :jack, :queen, :king]
# => [:ace, 2, 3, 4, 5, 6, 7, 8, 9, :jack, :queen, :king]
suit.product(rank).sample 1
# => [[:heart, :jack]]
suit.product(rank).sample 5
# => [[:club, 2], [:diamond, 2], [:spade, 7], [:club, 8], [:spade, :king]]

–Proctor

Erlang Thursday Bonus! Performace of erlang:length/1 on a list

A bonus Erlang Thursday for everyone.

Giving the Dallas/Fort Worth Erlang User group presentation last week, we had a couple of people new to Erlang make it to our meeting, and the question was raised:

Do lists have any smarts around knowing their length, or does it have to run through all the items to calculate the length?

I was 99% sure that Erlang has to run through the list every time, since it uses linked lists style data structures for it’s list, but wasn’t sure if there might be something smart in the implementation that I wasn’t aware of to speed up that functionality.

In putting together the regularly scheduled Erlang Thursday post for today, I realized I should have busted out timer:tc to demonstrate the behavior of erlang:length/1 by showing how long it takes to get the length of different lists.

So in honor of that question, and as a reminder to review it at the next user group meeting, I am documenting the behavior here. And remember, that the first item in the result tuple is the time in microseconds the operation took.

timer:tc(erlang, length, [lists:seq(1, 10)]).
{2,10}
timer:tc(erlang, length, [lists:seq(1, 1000)]).
{5,1000}
timer:tc(erlang, length, [lists:seq(1, 10000)]).
{41,10000}
timer:tc(erlang, length, [lists:seq(1, 100000)]).
{134,100000}
timer:tc(erlang, length, [lists:seq(1, 1000000)]).
{1918,1000000}
timer:tc(erlang, length, [lists:seq(1, 10000000)]).
{25139,10000000}
timer:tc(erlang, length, [lists:seq(1, 100000000)]).
{1368691,100000000}

After about 1000 items in a linked list, we start growing lineraly in the time it takes to count the items, so if it is not doing an actual traversal of all the items, it has the same scale of doing so as far as the order of operations (Big-O) goes.

–Proctor

Erlang Thursday – ordsets:intersection/2

Today’s Erlang Thursday looks some more at that ordsets module and covers ordsets:intersection/2.

ordsets:intersection/2 takes two ordered sets and returns a new ordered set that is the intersection of the two ordered sets provided. For those who don’t have a background wth set theory, all a set intersection is is the set of items that all the sets we are intersecting have in common.

OrderedSet1 = ordsets:from_list([1, 2, 1, 3, 2, 4, 4, 9]).
[1,2,3,4,9]
OrderedSet2 = ordsets:from_list([1, 3, 5, 7, 9]).
[1,3,5,7,9]
ordsets:intersection(OrderedSet1, OrderedSet2).
[1,3,9]
ordsets:intersection(OrderedSet2, OrderedSet1).
[1,3,9]

Because ordsets:intersection/2 looks for the common elements in the ordered sets, it is commutative, and as we see above, we get the same result regardless of which order we pass in the two ordered sets as arguments.

If there are no items in common, the returned result is an empty ordered set (really an empty list, but see last week’s post on ordsets:union/2 on the dangers of just using a list as a ordered set).

Evens = ordsets:from_list(lists:seq(2, 20, 2)).
[2,4,6,8,10,12,14,16,18,20]
Odds = ordsets:from_list(lists:seq(1, 20, 2)).
[1,3,5,7,9,11,13,15,17,19]
ordsets:intersection(OrderedSet2, ordsets:new()).
[]
ordsets:intersection(Evens, Odds).
[]

Erlang also provides ordsets:intersection/1, that takes a list of ordered sets as its argument, and returns the intersection of all the ordered sets in that list.

OrderedSet3 = ordsets:from_list([1, 1, 2, 3, 5, 8]).
[1,2,3,5,8]
ordsets:intersection([Evens, Odds, OrderedSet1]).
[]
ordsets:intersection([Odds, OrderedSet2, OrderedSet1]).
[1,3,9]
ordsets:intersection([Evens, OrderedSet1, OrderedSet3]).
[2]
ordsets:intersection([Odds, OrderedSet1, OrderedSet3]).
[1,3]

–Proctor