Ruby Tuesday – Array#compact

Today’s Ruby Tuesday in on Array#compact.

Array#compact operates against a given array and returns a new array with any nils removed.

array1 = [1, 2, nil, 3, nil, nil, 4, nil]
# => [1, 2, nil, 3, nil, nil, 4, nil]
array2 = array1.compact
# => [1, 2, 3, 4]
array1
# => [1, 2, nil, 3, nil, nil, 4, nil]
array2
# => [1, 2, 3, 4]
Array.new(7)
# => [nil, nil, nil, nil, nil, nil, nil]
Array.new(7).compact
# => []
[].compact
# => []
array_with_no_nils = [1, 2, 3, 4, 5]
# => [1, 2, 3, 4, 5]
compacted_array_with_no_nils = array_with_no_nils.compact
# => [1, 2, 3, 4, 5]
compacted_array_with_no_nils
# => [1, 2, 3, 4, 5]
array_with_no_nils
# => [1, 2, 3, 4, 5]

As seen in the examples above, Array#compact preserves the original order of the elements in the source array.

Array#compact only performs a shallow removal of any nils, and does not remove nils from any nested arrays.

mixed_type_array = [nil, :a, nil, nil, "b", [1, 2, nil, 3], nil, :c]
# => [nil, :a, nil, nil, "b", [1, 2, nil, 3], nil, :c]
mixed_type_array.compact
# => [:a, "b", [1, 2, nil, 3], :c]

And because nils in Ruby are falsey, we can do a quick sanity check about if Array#compact is looking at nils specifically, or falsey items in general, by creating a new Array filled with falses and calling compact on it.

Array.new(9){false}.compact
=> [false, false, false, false, false, false, false, false, false]

The Array class also defines Array#compact!, which modifies the underlying state of the Array it is being called on.

array3 = array1.dup
# => [1, 2, nil, 3, nil, nil, 4, nil]
array4 = array3.compact!
# => [1, 2, 3, 4]
array3
# => [1, 2, 3, 4]
array4
# => [1, 2, 3, 4]

As we can see in the above example, if the array compact! is being called on does have nils in it, the return value is the modified state of the Array.

But if you call Array#compact! on an array that does not have any nils in it, the return value of Array#compact! is nil.

Array.new(9){false}.compact!
# => nil

–Proctor

Erlang Thursday – ordsets:union/2

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

ordsets:union/2 takes two ordered sets and returns an merged ordered set of the arguments.

SetA = ordsets:from_list([1, 1, 2, 3, 5]).
% [1,2,3,5]
SetB = ordsets:new().
% []
SetC = ordsets:from_list([3, 1, 4, 1, 5, 9]).
% [1,3,4,5,9]
SetD = ordsets:from_list([a, b, c, d, e]).
% [a,b,c,d,e]
UnionAB = ordsets:union(SetA, SetB).
% [1,2,3,5]
UnionAC = ordsets:union(SetA, SetC).
% [1,2,3,4,5,9]

And because a string in Erlang is just a list of characters, we can also create ordered sets from strings, and then get a union of the unique characters that are in two strings.

ordsets:from_list("Kermit").
% "Keimrt"
ordsets:from_list([75, 101, 114, 109, 105, 116]).
% "Keimrt"
ordsets:from_list("Mississippi").
% "Mips"
ordsets:union(ordsets:from_list("Kermit"), ordsets:from_list("Mississippi")).
% "KMeimprst"

The ordsets modules also contains ordsets:union/1, which takes a list of ordered sets and returns the union of all the ordered sets in the list.

UnionAC = ordsets:union([SetA, SetC]).
% [1,2,3,4,5,9]
UnionABC = ordsets:union([SetB, SetC, SetA]).
% [1,2,3,4,5,9]
UnionABCD = ordsets:union([SetB, SetC, SetA, SetD]).
% [1,2,3,4,5,9,a,b,c,d,e]
UnionCD = ordsets:union([SetC, SetD]).
% [1,3,4,5,9,a,b,c,d,e]

WARNING: While the representation for an ordered set is just a list, if you pass a list to ordsets:union/2 you will not get what you expect, as it expects the items in each “ordered set” to actually be ordered and a set.

ordsets:union([1, 2, 3], [a, b, c]).
% [1,2,3,a,b,c]
ordsets:union([1, 1, 2, 3, 1, 2], [a, b, c]).
% [1,1,2,3,1,2,a,b,c]
ordsets:union([1, 1, 2, 3, 1, 2], [1, a, b, c]).
% [1,1,2,3,1,2,a,b,c]
ordsets:union([1, 1, 2, 3, 1, 2], [1, a, b, c, 1]).
% [1,1,2,3,1,2,a,b,c,1]

–Proctor

Ruby Tuesday – Array#-

Today’s Ruby Tuesday is on Array#-.

Array#-, also called Array Difference, operates against an array, takes another array as its argument, and returns the items in the source array that are not in the second array.

[1, 2, 3, 4, 5] - [1, 2, 3, 5, 8]
# => [4]
[1, 2, 3, 4, 5] - [1, 2, 3, 6, 7, 8]
# => [4, 5]
[1, 2, 3, 6, 7, 8] - [1, 2, 3, 4, 5]
# => [6, 7, 8]
["a", "b", "c", "d"] - ["a", "s", "d", "f"]
# => ["b", "c"]
["a", "b", "c", "d"] - []
# => ["a", "b", "c", "d"]
[] - ["a", "s", "d", "f"]
# => []

As it is doing a difference between the two arrays, let’s add in some duplicate items and see what happens.

[1, 1, 2, 3, 5] - [2, 4, 6, 8]
# => [1, 1, 3, 5]
[1, 2, 2, 3,] - [2, 4, 6, 8]
# => [1, 3]

Based on the results we see that if there was a duplicate item in the source list that wasn’t in the second array, then we leave all those items in the source list.

If we have an item that is duplicated in the first list, and has an entry in the second list as well, then all occurences of that item get removed.

If we wanted more of a set difference behavior, we would have to either call uniq on at least the first array, if not both, or call uniq on the result of the difference.

[1, 1, 2, 3, 5].uniq - [2, 4, 6, 8].uniq
# => [1, 3, 5]
(main)> ([1, 1, 2, 3, 5] - [2, 4, 6, 8]).uniq
# => [1, 3, 5]

–Proctor

Erlang Thrusday – queue:out/1

Today’s Erlang Thursday covers queue:out/1 from the queue module’s Original API.

queue:out/1 is one of my all time Queue fuctions, or methods, that I have seen, and that is across all the languages and libraries that I have encountered.

“What makes it so great?”, I can hear you asking.

That would be it’s combination of tuples, tagged tuples, immutability, forgivingness, and the fact that after seeing the result, it makes me wish more Queue implementations had an API like this.

First there have been many times in my past where either myself, or someone else, has forgotten to do a check to see if a queue is empty before trying to pop the first item from it, and that mistake has resulted in a not-so-nice runtime error.

queue:out/1 on the other hand, doesn’t trigger an error when you try to call it on an empty queue. Rather it returns a tagged tuple telling you that the queue you tried to call out on was empty, and the empty queue.

queue:out(queue:new()).
% {empty,{[],[]}} 

If we do pass in a non-empty queue, queue:out/1 returns a two tuple, with the first element being a tagged tuple that tells us we got a value out and the HEAD of the original queue, and for the second element, we get a new queue with the result of removing the first item.

Queue = queue:from_list([a, b, c, d]).
% {[d],[a,b,c]}
queue:out(Queue).
% {{value,a},{[d],[b,c]}}
Queue.
% {[d],[a,b,c]}
{{value, Head}, NewQueue} = queue:out(Queue).
% {{value,a},{[d],[b,c]}}
Queue.
% {[d],[a,b,c]}
Head.
% a
NewQueue.
% {[d],[b,c]}
queue:head(NewQueue).
% b

When dealing with the abstract notion of a queue across any language, the concept of a “pop” does two things, returns the top item of the queue, and modifies the queue to have that item removed.

Since Erlang queues are immutable, after you think about it for a few minutes, it starts to make sense that queue:out/1 handles both those behaviors of “pop” by returning both the item removed from the queue, and the new state of the queue with that item removed.

Erlang’s queue module also provides a function queue:out_r/1 which behaves the same as queue:out/1 except it operates off the last item in the queue, instead of the first item.

queue:out_r(queue:from_list([a, b, c, d])).
% {{value,d},{[c][/c],[a,b]}}
queue:out_r(queue:new()).
% {empty,{[],[]}}

I hope you found queue:out/1 as handy and as nice I have,

–Proctor

DFW Erlang – Erlang, Elixir, and LFE on a Raspberry Pi

For those of you who are, or will be, in the Dallas/Fort Worth area, this is your friendly reminder that next Wednesday, July 1st, will be our monthly DFW Erlang User Group meeting.

We have recently moved to be hosted by Improving Enterprises, and now meet on the first Wednesday of the month.

This upcoming meeting, I will be going over different Erlang VM languages running on a Raspberry Pi. We will show Erlang, Elixir, and LFE running and see how many processes we can manage to kick off on a Raspberry Pi with 435MB of memory.

To RSVP and join us you can find the meeting announcement on Meetup.com here.

If you can’t join us at this meeting, we would love to see you at a future meeting.

And lastly, I want to give a great big Thank You to Duncan McGreggor and Robert Virding for all of their help in getting LFE setup on a Raspberry Pi. And another Thank You to Duncan for coming up with a demo for LFE after asking him if he knew of any good LFE projects that show off a number of processes being spawned up and interacting to push the bounds of a Raspberry Pi. If you can’t make it to our user group, make sure to check out his project at https://github.com/oubiwann/laotzi-demo.

–Proctor

Ruby Tuesday – Array#&

Today’s Ruby Tuesday continues on with the Array class and takes a look at Array#*.

Array#* does a set intersection between two arrays1, and an empty array is treated as an empty set.

[1, 2, 3, 4, 5] & []
# => []
[1, 2, 3, 4, 5] & [1, 3, 5]
# => [1, 3, 5]
[1, 2, 3, 4, 5] & [1, 3, 5, 7, 9]
# => [1, 3, 5]
[:a, :b, :c, :d] & [:a, 2, :foo]
# => [:a]
[:d] & [:a, :b, :c, :d]
# => [:d]

The Ruby documentation pages mentions that it uses the eql? and hash methods to determine if two elements are equal, so the elements only have to have the same value and not be the same reference.

[[1, 2], [3, 4], ["a", "b"]] & [[3, 4]]
# => [[3, 4]]
[3, 4].equal? [3, 4]
# => false
[3, 4].eql? [3, 4]
# => true

Array#& also keeps the order of the items as found in the original list for the items in the return value.

["a", "b", "c", "d", "e"] & ["c", "a", "t"]
# => ["a", "c"]

And as mentioned above, it is a set intersection, so no matter how many times an item appears in either array, it is only returned once.

[1, 2, 1, 3] & [1, 2]
# => [1, 2]
[1, 2, 1, 3] & [1, 1, 2]
# => [1, 2]
[1, 2, 1, 3] & [1, 1]
# => [1]

And by turning a String into an Array of characters, we can find all characters that are common between two strings.

"Supercalifragilisticexpialidocious".chars & "Me Ol' Bamboo".chars
# => ["e", "a", "l", "o"]

–Proctor


1. For those who are unfamiliar with what a set intersection is, it is finds all unique elements that are common between the two arrays.

Erlang Thursday – queue:split/2

Today’s Erlang Thursday is on queue:split/2 from the queue modules Original API.

queue:split/2 takes two arguments. The first argument being a integer N from 0 to X, where X is number of items in the queue, and the second argument is the queue that we wish to split. The return value is a two-tuple with a the first item being a queue of the first N items, and the second item in the tuple is a queue of the rest of the items.

QueueOne = queue:from_list([a, 1, b, 2, c, 3, 4]).
% {[4,3,c],[a,1,b,2]}
queue:split(4, QueueOne).
% {{[2],[a,1,b]},{[4,3],[c][/c]}}
queue:split(0, QueueOne).
% {{[],[]},{[4,3,c],[a,1,b,2]}}
queue:split(1, QueueOne).
% {{[],[a]},{[4,3,c],[1,b,2]}}
queue:split(7, QueueOne).
% {{[4,3,c],[a,1,b,2]},{[],[]}}
queue:split(15, QueueOne).
% ** exception error: bad argument
%      in function  queue:split/2
%         called as queue:split(15,{[4,3,c],[a,1,b,2]})
{SplitFirst, SplitSecond} = queue:split(3, QueueOne).
% {{[b,1],[a]},{[4,3,c],[2]}}
SplitFirst.
% {[b,1],[a]}
SplitSecond.
% {[4,3,c],[2]}
queue:peek(SplitFirst).
% {value,a}
queue:peek(SplitSecond).
% {value,2}

Erlang also provides a queue:join/2 function that takes two queues, and returns a new queue, with the queue that was passed as the second argument appended to the queue passed in as the first argument.

queue:join(SplitFirst, SplitSecond).
% {[4,3,c],[a,1,b,2]}
queue:join(SplitSecond, SplitFirst).
% {[b,1],[2,c,3,4,a]}
queue:join(queue:new(), SplitFirst).
% {[b,1],[a]}
queue:join(queue:new(), queue:new()).
% {[],[]}

–Proctor

Ruby Tuesday – Array#*

Today’s Ruby Tuesday cover’s Array#*.

Array#* either takes a integer, N, as its argument, in which case it concatenates N copies of the array together and uses the result as it return value.

[1, 2, 3, 4, 5] * 3
% => [1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5]
["a", "b", "c"] * 4
% => ["a", "b", "c", "a", "b", "c", "a", "b", "c", "a", "b", "c"]
[1, [:a, [:b, [:c]]]] * 2
% => [1, [:a, [:b, [:c]]], 1, [:a, [:b, [:c]]]]

Or it can take a string as its argument, in which case, it returns a flattened join of the items in the array with the string argument as the separator.

["a", "b", "c"] * ","
% => "a,b,c"
["a", "b", "c"] * "at"
% => "aatbatc"
[1, 2, 3, 4, 5] * ''
% => "12345"
[:x, :y, :z] * ';'
% => "x;y;z"
[[:a, 1], [:b, 2], [:c, 3]] * ';'
% => "a;1;b;2;c;3"
[1, [:a, [:b, [:c]]]] * ';'
% => "1;a;b;c"

Notice how multiplying by a string returns a flattened array joined together, instead of just the top level elements of an array with to_s called on them joined together.

–Proctor

Erlang Thursday – queue:peek/1

For today’s Erlang Thursday we continue looking at the queue module and look at queue:peek/1 from the Extended API.

queue:peek/1 takes a queue as it’s argument and returns either the atom empty if the queue is empty, or {value, Item} where Item is the item at the head of the queue.

QueueOne = queue:from_list([1, 2, 3, 4, 5]).
% {[5,4],[1,2,3]}
queue:peek(QueueOne).
% {value,1}
QueueOne.
% {[5,4],[1,2,3]}
EmptyQueue = queue:new().
% {[],[]}
queue:peek(EmptyQueue).
% empty

queue:peek/1 does not modify the existing queue at all either, so we can call it once as seen above, or multiple times as below, and the queue we peeked at doesn’t change.

QueueTwo = queue:from_list([a, b, c, d, e, f]).
% {[f,e],[a,b,c,d]}
queue:peek(QueueTwo).
% {value,a}
queue:peek(QueueTwo).
% {value,a}
queue:peek(QueueTwo).
% {value,a}
QueueTwo.
% {[f,e],[a,b,c,d]}

And unlike we saw in the previous Erlang Thursday on queue:head/1, we can safely peek at an empty queue instead of getting an exception.

queue:head(EmptyQueue).
% ** exception error: empty
%      in function  queue:head/1
%         called as queue:head({[],[]})
queue:peek(EmptyQueue).
% empty

Erlang’s queue module also contains queue:peek_r/1 which will peek at the element at the rear of the queue.

queue:peek_r(EmptyQueue).
% empty
queue:peek_r(QueueOne).
% {value,5}
queue:peek_r(QueueOne).
% {value,5}
queue:peek_r(QueueOne).
% {value,5}
queue:peek_r(QueueTwo).
% {value,f}
QueueTwo.
% {[f,e],[a,b,c,d]}
QueueOne.
% {[5,4],[1,2,3]}
EmptyQueue.
% {[],[]}

–Proctor

Ruby Tuesday – Array#first

As we continue looking to see how Ruby’s Array class can be seen as a queue, we take a look at Array#first.

Array#first returns the first element of an Array, or nil if the array is empty.

[1, 2 ,3, 4, 5].first
# => 1
[].first
# => nil
[{:a => 1}, :b, [1, 2, 3]].first
# => {:a=>1}

While this in and of itself is nothing spectacular, what it gets us is a way of having Command/Query Separation1, or CQS for short.

Why care about Command/Query Separation?

First, by using it we can start to take a more functional approach to our design. We can “peek” at the first element of an array, and keep peeking to our hearts content and never worry about modifying the state of the queue.

Second, when it is time to “pop” the next element off the queue, we can have the result of the “pop” command be to return a new queue object that is the result of dropping the first item from the array.

This allows us to empty a queue without modifying the original queue.

my_queue = [1, 2, 3, 4, 5]
# => [1, 2, 3, 4, 5]
my_queue.first #peek
# => 1
my_queue.first #peek again
# => 1
after_pop = my_queue.drop(1)
# => [2, 3, 4, 5]
after_pop
# => [2, 3, 4, 5]
my_queue
# => [1, 2, 3, 4, 5]

–Proctor


1. Command/Query Separation states that a method should either return a value, or modify state, but never do both.