User Tools

Site Tools


CSci 326 Lab #2 - Enumerations

Purpose: to gain experience with the functions that operate on enumerable collections. These problems are based on the examples at ElixirSchool and you might go through some of those on your own to get the ideas down.

For this lab, either write down your results and turn it in, or email a transcript showing the results along with answers for the questions in #4, #5, and #7.

Part 1 - Enum:

  1. This expression will list every function available in the module so start iex and give it a try:
    Enum.__info__(:functions) |> Enum.each(fn({fname, arity}) -> IO.puts "#{fname}/#{arity}" end)

    Let's break this down:

    • Enum.__info__(:functions)
      returns a keyword list containing the names of all the functions in the module (this works for any module by the way). This list is apparently too long for iex to show the entirety (maybe it gets tired, poor thing). So we need to process it somehow…
    • This operator |> is called the pipe operator. It is awesome (Joe Armstrong said so!)…it simply takes the output of one command and makes it the input of the next. Transforming data through series of piped commands is a common Elixir idiom.
    • Enum.each is similar to but it does not return its results as a list. The anonymous function we're passing to it takes a tuple from the keyword list and simply prints it out as a more readable string.
  2. Enum.all? returns true only if a predicate applied to each element of a collection returns true for the entire collection, otherwise it returns false. Try these:
    Enum.all? ["foo", "bar", "hello"], fn(s) -> String.length(s) > 1 end
    Enum.all? ["foo", "bar", "hello"], fn(s) -> String.length(s) > 3 end
  3. All the examples use lists, but the Enum module works for other enumerables, like map. Try this one out:
    Enum.each %{"jan" => 31, "feb" => 28, "mar" =>"31", "apr" => 30}, fn({key, _value}) -> IO.puts(key) end
  4. Now try this one:
    Enum.each %{"jan" => 31, "feb" => 28, "mar" =>"31", "apr" => 30}, fn({_key, value}) -> IO.puts(value) end

    Looking at the results of the last two commands, what can we say about how maps store (key, value) pairs in memory?

  5. Apparently, to iterate over maps, we need an anonymous function that takes a {key, value} tuple. Come up with an example of your own for or Enum.reduce that work on maps. Show your results to the instructor.
  6. First define the function odd?
    odd? = &(rem(&1, 2) != 0)

    Now use it with Enum.filter:

    Enum.filter(1..10, odd?)
  7. Now try this monstrosity:
    1..100_000 |> * 3)) |> Enum.filter(odd?) |> Enum.sum()

    See if you can describe the operation in English.

  8. The sort function uses the mergesort algorithm using Elixir's term order. To see this in action, try:
    Enum.sort([:foo, "bar", Enum, -1, 4])
  9. Another version of sort lets you pass a function to change the default sort mechanism. Try these two to see the difference:
    Enum.sort ["x", "yz", "abc", "klmn", "defgh"]
    Enum.sort ["x", "yz", "abc", "klmn", "defgh"], fn(x, y) -> (String.length x) < (String.length y) end

Part 2 - Strings:

  1. Have a look at the docs for the Try out the examples for the functions codepoints/1, ends_with/2, slice/2 and split/1 in iex.
  2. This expression uses the pipe operator and functions from the String and List modules to convert a monetary amount stored as a string into the equivalent number. Try it out:
    "$34.56" |> String.split("$") |> List.last |> String.to_float

Have a look at the docs for the String, List, and Enum modules while trying the next two homework assignments.

cs326/lab2.txt · Last modified: 2021/09/24 03:13 by scarl