Erlang Thursday – calendar:date_to_gregorian_days/3

Today’s Erlang Thursday covers calendar:date_to_gregorian_days/3.

As we saw in last week’s Erlang Thursday on calendar:day_of_the_week/3 when we were looking at some error messages, we saw that the errors were coming from calendar:date_to_gregorian_days/3.

calendar:day_of_the_week(0, 0, 0).
% ** exception error: no function clause matching calendar:date_to_gregorian_days(0,0,0) (calendar.erl, line 114)
%      in function  calendar:day_of_the_week/3 (calendar.erl, line 151)
calendar:day_of_the_week(1970, 2, 31).
% ** exception error: no true branch found when evaluating an if expression
%      in function  calendar:date_to_gregorian_days/3 (calendar.erl, line 116)
%      in call from calendar:day_of_the_week/3 (calendar.erl, line 151)
calendar:day_of_the_week(1970, 13, 2).
% ** exception error: no function clause matching calendar:last_day_of_the_month1(1970,13) (calendar.erl, line 243)
%      in function  calendar:date_to_gregorian_days/3 (calendar.erl, line 115)
%      in call from calendar:day_of_the_week/3 (calendar.erl, line 151)

I promised you at the end of that post we would take a deeper look at calendar:date_to_gregorian_days/3 next time, so let’s fulfill that promise.

calendar:date_to_gregorian_days/3 takes three arguments, a non-negative integer for the year, an integer between 1 and 12 (inclusive) for the month, and an integer between 1 and 31 (inclusive) for the day of the month, and returns the number of days since 0000-01-01 in the Gregorian calendar.

calendar:date_to_gregorian_days(2015, 4, 16).
% 736069
calendar:date_to_gregorian_days(0, 1, 1).
% 0
calendar:date_to_gregorian_days(1, 1, 1).
% 366
calendar:date_to_gregorian_days(1970, 1, 1).
% 719528
calendar:date_to_gregorian_days(1999, 12, 31).
% 730484

There is also a version calendar:date_to_gregorian_days/1, that takes a tuple of year, month, and day available if your code already has the date in tuple format.

calendar:date_to_gregorian_days({2015, 4, 16}).
% 736069
calendar:date_to_gregorian_days({0, 1, 1}).
% 0
calendar:date_to_gregorian_days({1, 1, 1}).
% 366

And if we pass something invalid to calendar:date_to_gregorian_days/1, we see that it is calling calendar:date_to_gregorian_days/3. So it is just a nice helper function that does the pattern match destructing for us.

calendar:date_to_gregorian_days({1, 1, 0}).
** exception error: no function clause matching calendar:date_to_gregorian_days(1,1,0) (calendar.erl, line 114)

–Proctor

,

Leave a Comment

Ruby Tuesday – Date#jd

Today’s Ruby Tuesday covers Date#jd.

Date#jd returns the number of days since the beginning of the Julian calendar.

require 'date'
# => true

Date.new.jd
# => 0
Date.new(2015, 04, 14).jd
# => 2457127
Date.new(0, 1, 1).jd
# => 1721058

If you notice above, we get 1721058 for the days since the start of the Julian calendar. One thing to notice is that we can pass an optional “Julian day number which denotes the day of calendar reform” to Date#new. If we pass in the constant Date::GREGORIAN to new, and then call Date#jd on the result, we get a different value coming back for the number of days since the start of the Julian calendar, 1721060 vs 1721058.

Date.new(0, 1, 1, Date::GREGORIAN).jd
=> 1721060

While Ruby does not have a corresponding method for getting the number of days since the start of the Gregorian calendar, we can do a difference between the number of Julian days for a date and the number of Julian days for the date 0000-01-01. But be warned, as we just saw above, to get an accurate number, we need to specify that we want 0000-01-01 to be the Gregorian version of that date.

Date.new(2015, 04, 14).jd - Date.new(0, 1, 1).jd
# => 736069
Date.new(2015, 04, 14).jd - Date.new(0, 1, 1, Date::GREGORIAN).jd
# => 736067
Date.new(2015, 04, 14, Date::GREGORIAN).jd - Date.new(0, 1, 1, Date::GREGORIAN).jd
# => 736067

If we just construct a new Date, and do not specify and Julian start date, we notice that we can see the number of Julian days in the constructor, and if we specify we want the date to be Gregorian calendar based, we can see the number of Julian days is different there as well.

Date.new(0, 1, 1)
# => #<Date: 0000-01-01 ((1721058j,0s,0n),+0s,2299161j)>
Date.new(0, 1, 1, Date::GREGORIAN)
# => #<Date: 0000-01-01 ((1721060j,0s,0n),+0s,-Infj)>

Hope this shined as little bit of knowledge on Ruby Dates for you as it did me.

–Proctor

,

Leave a Comment

Erlang Thursday – calendar:day_of_the_week/3

Today’s Erlang Thursday is covers calendar:day_of_the_week/3.

calendar:day_of_the_week/3 allows you to get the day of the week a day occurred on when passed a year, a month and a day.

The first argument represents the year and must be a non-negative integer. The second argument is the month and must be an integer value between 1 and 12 inclusive, representing the 12 months of the Gregorian Calendar, with January being month one. The final argument to calendar:day_of_the_week/3 is the date, and is expected to be a integer between 1 and 31 inclusive.

calendar:day_of_the_week/3 returns an integer value in between 1 and 7 inclusive, with a return value of 1 representing Monday, and a 7 being Sunday.

calendar:day_of_the_week(1, 1, 1).
% 1
calendar:day_of_the_week(1970, 1, 1).
% 4
calendar:day_of_the_week(1999, 12, 31).
% 5
calendar:day_of_the_week(0, 1, 1).
% 6

As you can see that the publish date of this Erlang Thursday post, 2015-04-09, returns a 4, which is in fact a Thursday according to Erlang.

calendar:day_of_the_week(2015, 4, 9).
% 4

There is also a calendar:day_of_the_week/1 function which has all the same constraints but instead of taking three arguments, takes one argument that is a three-tuple of the year, month, and day.

calendar:day_of_the_week({2015, 4, 9}).
% 4
calendar:day_of_the_week({1970, 1, 1}).
% 4
calendar:day_of_the_week({1999, 12, 31}).
% 5

And in the spirit of helping to recognize error messages when we see them, let’s take a look at what we get when we pass some invalid inputs to calendar:day_of_the_week/3.

calendar:day_of_the_week(0, 0, 0).
% ** exception error: no function clause matching calendar:date_to_gregorian_days(0,0,0) (calendar.erl, line 114)
%      in function  calendar:day_of_the_week/3 (calendar.erl, line 151)
calendar:day_of_the_week(1970, 2, 31).
% ** exception error: no true branch found when evaluating an if expression
%      in function  calendar:date_to_gregorian_days/3 (calendar.erl, line 116)
%      in call from calendar:day_of_the_week/3 (calendar.erl, line 151)
calendar:day_of_the_week(1970, 13, 2).
% ** exception error: no function clause matching calendar:last_day_of_the_month1(1970,13) (calendar.erl, line 243)
%      in function  calendar:date_to_gregorian_days/3 (calendar.erl, line 115)
%      in call from calendar:day_of_the_week/3 (calendar.erl, line 151)

If you look at the error messages you see that calendar:day_of_the_week/3 calls calendar:date_to_gregorian_days/3, which we will cover in next week’s Erlang Thursday.

–Proctor

,

Leave a Comment

Ruby Tuesday – Date#wday

Today’s Ruby Tuesday is on Date#wday.

Date#wday returns an integer value for the day of the week that the day falls on.

Date.new(2015, 4, 7).wday
# => 2
Date.new(1970, 1, 1).wday
# => 4
Date.new(1, 1, 1).wday
# => 6

The values that Date#wday can return will be between 0-6, with 0 being Sunday.

Date.new(2015, 4, 5).wday
# => 0
Date.new(2015, 4, 5).sunday?
# => true
Date.new(2015, 4, 11).wday
# => 6
Date.new(2015, 4, 11).saturday?
# => true

–Proctor

,

Leave a Comment

Erlang Thurday – lists:delete/2

Today’s Erlang Thursday in lists:delete/2.

lists:delete/2 takes a Erlang term as it’s first argument, and will remove that item from the list passed in as the second argument.

lists:delete(1, [8, 7, 6, 5, 4, 3, 2, 1]).
% [8,7,6,5,4,3,2]
lists:delete(4, [1, 1, 2, 3, 5, 8]).
% [1,1,2,3,5,8]
lists:delete(72, "Hello World!").
% "ello World!"
lists:delete(d, [a, b, c, d]).
% [a,b,c]
lists:delete(4, []).
% []
lists:delete({b, 2}, [{a, 1}, {b, 2}, {c, 3}]).
% [{a,1},{c,3}]
lists:delete([1, 2, 3], [[4, 5, 6], [7, 8, 9], [1, 2, 3]]).
% [[4,5,6],[7,8,9]]

Note that lists:delete/2 only removes the first item found in the list, and leaves any other occurrences of the item in the list.

€lists:delete(1, [1, 1, 2, 3, 5, 8]).
% [1,2,3,5,8]

As lists:delete/2 was a easy function to demonstrate, and leaving it at this would be a very short post, I thought it might be worth showing a how you might write a very naive1 implementation of lists:delete/2 yourself.

-module(my_lists).

-export([delete/2]).

delete(Item, List) ->
    delete(Item, [], List).

delete(Item, Checked, [Item|Rest]) ->
    lists:reverse(Checked) ++ Rest;
delete(Item, Checked, [Head|Rest]) ->
    delete(Item, [Head | Checked], Rest);
delete(_Item, Checked, []) ->
    lists:reverse(Checked).

Let’s start with our delete function as we expect it to be called from the outside world.

my_lists:delete/2 is the nice API function that just calls delete/3 which is a “private” function (not exported) so the consumer doesn’t have to worry about passing in the accumulator for the items we have checked so far, which we pass as an empty list for the initial value.

-module(my_lists).

-export([delete/2]).

delete(Item, List) ->
    delete(Item, [], List).

The first function clause of delete/3 uses pattern matching to check if the item we want to delete is also the first item in the rest of the list to check. If the pattern match succeeds, we have found the first occurrence of the item to remove! We can stop processing the list and return the result, which is the reverse of the list of items we have checked so far combined with the rest of the items we never got around to checking.

delete(Item, Checked, [Item|Rest]) ->
    lists:reverse(Checked) ++ Rest;

The second clause “knows” that the item we are wanting to delete and the first item in the rest of the list don’t match. How does it “know”? Because if they did match, the first clause would have matched and this clause would not have been evaluated. As we haven’t found the item to remove, we add the item held by Head to the list of Checked items, and then continue calling delete/3. The fact that we are passing a new list of the checked items by prepending Head to the list in Checked is why we need to reverse Checked in the first and third function clauses.

delete(Item, Checked, [Head|Rest]) ->
    delete(Item, [Head | Checked], Rest);

The third, and final, clause of delete/3 has reached the end of the list and not found the item, so we just return the list we have reversed it.

delete(_Item, Checked, []) ->
    lists:reverse(Checked).

There you have it, a very naive1 implementation of your very own version of lists:delete/2.

–Proctor

1. Naive because this is not optimized for performance, or exhaustively tested for completely accurate behavior of lists:delete/2. back

,

Leave a Comment

Ruby Tuesday – Array#delete

Today’s Ruby Tuesday covers Array#delete.

Array#delete removes all items in the array that are equal to the object passed as an argument to the method.

list = [1, 2, 1, 3, 1, 5]
# => [1, 2, 1, 3, 1, 5]
list.delete(1)
# => 1
list
# => [2, 3, 5]
list.delete(3)
# => 3
list
# => [2, 5]

mississippi = "Mississippi".chars
# => ["M", "i", "s", "s", "i", "s", "s", "i", "p", "p", "i"]
mississippi.delete("s")
# => "s"
mississippi
# => ["M", "i", "i", "i", "p", "p", "i"]

Array#delete by default returns nil if the item was not found in the list.

no_fours = [1, 2, 3, 5, 6, 7]
# => [1, 2, 3, 5, 6, 7]
no_fours.delete(4)
# => nil

But if you decide to use Array#delete to remove nils from the array, you may not be able to check that it was removed because nil is returned as the value that was removed.

contains_nil = [1, "a", nil, :foo]
# => [1, "a", nil, :foo]
contains_nil.delete(nil)
# => nil
contains_nil
# => [1, "a", :foo]

If you come across that scenario, Array#delete allows you to specify a block that gets called if the item was not found in the array.

contains_nil2 = [1, "a", nil, :foo]
# => [1, "a", nil, :foo]
contains_nil2.delete(nil) {:bar}
# => nil
contains_nil2
# => [1, "a", :foo]
contains_nil2.delete(nil) {:bar}
# => :bar

As mentioned above, Array#delete removes all items that are equal to the argument passed in. The catch is Ruby has three different equality comparisons: ==, eql?, and equal?. So let’s try a couple of different scenarios to see which equality operator Ruby uses when doing an equality check.

mississippi = "Mississippi".chars
# => ["M", "i", "s", "s", "i", "s", "s", "i", "p", "p", "i"]
mississippi.delete("s")
# => "s"
"s" == "s"
# => true
"s".eql? "s"
# => true
"s".equal? "s"
# => false

So it looks like it is not equal?, but we still have == and eql? left that it could be, so let’s try another scenario.

integers = [1, 2, 3, 4]
# => [1, 2, 3, 4]
integers.delete(1.0)
# => 1
integers
# => [2, 3, 4]
1 == 1.0
# => true
1.eql? 1.0
# => false
1.equal? 1.0
# => false

As we can see here, 1 was removed when 1.0 was passed as an argument, so we see that Array#delete uses the == equality check to determine if the items are equal.

–Proctor

,

Leave a Comment

Erlang Thursday – erlang:list_to_atom/1

Today’s Erlang Thursday covers erlang:list_to_atom/1.

erlang:list_to_atom/1 takes a string, and returns an Erlang atom.

list_to_atom("foo").
% foo
list_to_atom("Foo").
% 'Foo'
list_to_atom("Foo_bar").
% 'Foo_bar'
list_to_atom("foo_bar").
% foo_bar
list_to_atom("foo"++"bar").
% foobar
list_to_atom("Erlang").
% 'Erlang'
list_to_atom("Elixir").
% 'Elixir'

This can be useful if you are having to create keys or identifiers based off strings read in from outside the system, such as parsing a CSV style header.

lists:map(fun erlang:list_to_atom/1,
          string:tokens("firstName,lastName,age,gender,preferredName,dateOfBirth", ",")).
% [firstName,lastName,age,gender,preferredName,dateOfBirth]

You do need to be careful when using erlang:list_to_atom/1 on strings acquired from the outside world of your program, as it only handles strings with character values under 256. But any character value1 under 256 is fair game to be turned into an atom.

list_to_atom("Joe, Mike, and Robert").
% 'Joe, Mike, and Robert'
list_to_atom("it's").
% 'it\'s'
list_to_atom("hey\n").
% 'hey\n'€
list_to_atom("with_supported_char"++[255]).
% with_supported_charÿ
list_to_atom("with_non_supported_char"++[256]).
% ** exception error: bad argument
%      in function  list_to_atom/1
%         called as list_to_atom([119,105,116,104,95,110,111,110,95,115,117,112,112,111,114,
%                                 116,101,100,95,99,104,97,114,256])

–Proctor


1. Remember that character values are non-negative integer values as well. 0-255 inclusive. back

,

Leave a Comment

Ruby Tuesday – String#to_sym

Today’s Ruby Tuesday covers String#to_sym.

String#to_sym operates on a String object, and turns the string into a Symbol.

Why would someone want to have a Symbol instead of a String?

The main reason is that Symbols are created once for the lifetime of a program, and use the same reference. Every reference to the symbol :foo refers to the same instance of :foo, and it doesn’t matter when, or where, in the program lifetime it is.

Strings on the other hand are unique objects, so two strings of the same value are not necessarily the same object, and depends on when, where, and how they were created.

"foo".to_sym
# => :foo
"Foo".to_sym
# => :Foo
"foo".__id__ == "foo".__id__
# => false
:foo.__id__ == :foo.__id__
# => true

One case where this might be useful is where you have to tokenize strings, and are going to want to use them as keys for a map. Think header columns in a CSV file, but please don’t write your own CSV parser, as Ruby has a nice one built in.

"firstName,lastName,preferred name,age".split(",").map(&:to_sym)
# => [:firstName, :lastName, :"preferred name", :age]

The other place where you might want to use String#to_sym is when you are trying to create Symbols that cannot easily be created by just using the normal symbol notation.

":foo".to_sym
# => :":foo"
"peanut butter".to_sym
# => :"peanut butter"

–Proctor

,

Leave a Comment

Erlang Thurday – ordsets:is_disjoint/2

Today’s Erlang Thurday covers ordsets:is_disjoint/2.

There are times in your in your coding day where you have problems where you need to know if given a list of items that none of those items appear in a secondary list.

Your first intuition might be to write out the code as described, like such:

not( lists:any(fun(Item) -> lists:member(Item, [1, 3, 5, 7]) end, [2, 4, 6])).
% true

And while that is accurate, if you redefine your problem in more mathematical terms, you can start to think in sets. When you start to think in terms of sets, you realize that you can check to see if the intersection of the two sets is the empty set.

ordsets:intersection([1, 3, 5, 7], [2, 4, 6]) =:= [].
% true

This is becoming not only more concise, but also more explicit about what you are trying to check.

We can do better still, by checking if the lists are disjoint sets. Enter ordsets:is_disjoint/2.

ordsets:is_disjoint/2 takes two lists, and returns true if no elements are in common.

ordsets:is_disjoint([1, 3, 5, 7], [2, 4, 6]).
% true
ordsets:is_disjoint([1, 2, 3, 5, 7], [2, 4, 6]).
% false

Because ordsets:is_disjoint/2 operates against two lists, we do not have to make sure the elements are unique prior to calling ordsets:disjoint/2.

ordsets:is_disjoint([1, 1, 3, 5, 7, 5, 3], [2, 4, 2, 2, 6]).
% true
€ordsets:is_disjoint([1, 2, 3, 5, 7], [2, 4, 2, 2, 6]).
% false

And if either list passed to ordsets:is_disjoint/2 is an empty list, the result is that the lists are disjoint.

ordsets:is_disjoint([1, 2, 3, 5, 7], []).
% true
ordsets:is_disjoint([], [2, 4, 6]).
% true
ordsets:is_disjoint([], []).
% true

And if you are curious, by running ordsets:is_disjoint/2 through timer:tc/3, we can see that as soon as Erlang knows that the sets are not disjoint, it returns false. And if you remember from the previous Erlang Thrusday on timer:tc/3, the return value is a tuple with the first element being the number of microseconds it took to complete.

timer:tc(ordsets, is_disjoint, [lists:seq(1, 1000000), lists:seq(2000000, 3000000)]).
% {19032,true}
€timer:tc(ordsets, is_disjoint, [lists:seq(1, 1000000), lists:seq(1, 3000000)]).
% {2,false}

–Proctor

,

Leave a Comment

Ruby Tuesday – Set#disjoint?

Today’s Ruby Tuesday is on Set#disjoint?.

To start using Sets, we first need to require Set.

require 'set'

Set#disjoint? is useful when you want to make sure a group of items is not in another group of items.

Without using Set#disjoint? you would probably be writing something like the following:

[1, 3, 1, 5, 7].none? { |item| [2, 4, 6, 8].include? item }
# => true

While this works, it does not make the intent of what you are trying to do explicit, which is where Set#disjoint? comes in.

Set#disjoint? operates against a set, and takes another Set as it’s argument, and checks to see if there is no common element between the two sets.

[1, 3, 1, 5, 7].to_set.disjoint? [2, 4, 6, 8].to_set
# => true
[1, 2, 3].to_set.disjoint? [1, 3, 5, 7].to_set
# => false

If a nil is present in both sets, Set#disjoint? treats the nils as equal and returns false.

[2, nil].to_set.disjoint? [1, 3, 5, 7, nil].to_set
=> false

Set#disjoint? works against empty sets as well.

[].to_set.disjoint? [1, 2, 3].to_set
# => true
[1, 2, 3].to_set.disjoint? [].to_set
# => true

If two empty sets are passed to Set#disjoint?, it returns true, as both sets have no elements, and therefore no elements in common.

[].to_set.disjoint? [].to_set
# => true

–Proctor

,

Leave a Comment