This is Part 4 of learning about the Enum module, picking up from where Part 3 left off. We'll finish the Enum module by covering all the functions we haven't covered yet.

Enum.sort/1

The Enum.sort/1 function sorts the elements in an enumerable using Elixir's default comparison logic. It uses a merge sort algorithm to do the sorting.

Here are some examples.

#Sort a scrambled list of numbers
iex> Enum.sort([4, 10, 22, -8, 5, 12, 10, -2, 0, 5])
[-8, -2, 0, 4, 5, 5, 10, 10, 12, 22]
#Sort an ordered list of numbers
iex> Enum.sort(1..10)
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
#Sort using Elixir's default type comparison
iex> Enum.sort(["Bob", :ok, 3.14, 3, ["a", "b"], true])
[3, 3.14, :ok, true, ["a", "b"], "Bob"]

Remember that Elixir has rules to compare different data types, where all values of a particular type are always greater than or less than the values of other types.

Javascript has an equivalent function on an array, but it does in-place sorting instead of returning a different sorted array.

let numbers = [1, 2, 3, 4, 5];

numbers.sort();

C# has a function in the List<T> class called Sort(), which sorts the list in place rather than returning a different sorted list. There is another equivalent function in the LINQ extension methods called IEnumerable.OrderBy(), which takes a function that determines which value to sort by.

List<int> numbers = new List<int>() {1, 2, 3, 4, 5);

List<int> sortedNumbers = numbers.OrderBy(number => number).ToList();

Enum.sort/2

Just like Enum.min/3 and Enum.max/3 allow the caller to pass a function that implements custom comparison logic, so does Enum.sort/2. The function passed in as a second parameter compares two elements, which is used by the sorting algorithm to order the elements. This allows you to control how the elements are sorted.

This example will result in odd numbers being greater than even numbers during the sort operation, but odd and even numbers will be sorted numerically within their group.

iex> Enum.sort(1..10, fn
...>    (a, b) when rem(a, 2) == rem(b, 2) -> a <= b
...>    (a, b) -> rem(a, 2) <= rem(b, 2)
...> end)
[2, 4, 6, 8, 10, 1, 3, 5, 7, 9]

If we want the odd numbers to be less than the even numbers, we just have to reverse the boolean comparison in the second function clause.

iex> Enum.sort(1..10, fn
...>    (a, b) when rem(a, 2) == rem(b, 2) -> a <= b
...>    (a, b) -> rem(a, 2) >= rem(b, 2)
...> end)
[1, 3, 5, 7, 9, 2, 4, 6, 8, 10]

Javascript does not have an equivalent to this function, but the lodash library does with the orderBy() function. The following example sorts first by whether the number is even (even numbers are less than odd numbers) and then by numerical value.

let numbers = [1, 2, 3, 4, 5];

const isEven = number => number % 2;
const numberValue = number => number;

//The result is [2, 4, 1, 3, 5]
let sortedNumbers = _.sortBy(numbers, [isEven, numberValue]);

C# has a version of IEnumerable.OrderBy() in the LINQ extension methods that also accepts a comparison delegate to do the comparison. However, since the example would be relatively complex and requires a significant amount of code, I'm not going to go into it any further here.

Enum.sort_by/3

The Enum.sort_by/3 function provides another way to perform sorting. We need to pass it an enumerable, a mapper function, and a sorter function. The mapper function maps the enumerable elements like Enum.map/2 and the sorter function compares the elements in mapped collection. Instead of returning the sorted-mapped collection, the Enum.sort_by/3 function returns the equivalent original elements in sorted order.

The sorter function is an optional parameter and by default it is set to the <=/2 function in the Kernel module, which corresponds to the <= operator. This means that the mapped elements will be sorted by default Elixir sort order.

This function is a bit weird to me and I'm having a hard time figuring out why I would ever use this function instead of the other sort functions. That makes me think that I'm missing something about the potential of this function. I suspect that I could do some interesting things with it if I could think of a good use case for it.

So until I realize the true potential of this function, I'm going to show you how it works. First I'm going to sort a ranges by "evenness". Even numbers are less than odd numbers, but even and odd numbers are all equal to each other.

iex> evenness_value = fn number -> rem(number, 2) end
#Function<6.99386804/1 in :erl_eval.expr/5>
iex> Enum.sort_by(1..10, &(evenness_value.(&1)))
[2, 4, 6, 8, 10, 1, 3, 5, 7, 9]

This example only provides a mapping function, allowing the default sort to be used. I'm going to walk us through what happens here.

  1. The range 1..10 is first mapped to a list of "evenness" values, which are 0 for even numbers and 1 for odd numbers. So that looks like [1, 0, 1, 0, 1, 0, 1, 0, 1, 0].
  2. That list is then sorted by the default sorter function to get [0, 0, 0, 0, 0, 1, 1, 1, 1, 1].
  3. Then through some kind of magic, those are mapped back to the original values (a reverse mapping) and that results in [2, 4, 6, 8, 10, 1, 3, 5, 7, 9].

I don't know this for sure, but I suspect that internally the Enum.sort_by/3 function uses a list of tuples that track the relationship between the original and mapped values, like so: [{1, 1}, {0, 2}, {1, 3}, {0, 4}, {1, 5}, {0, 6}, {1, 7}, {0, 8}, {1, 9}, {0, 10}]. That would allow the function to sort the mapped values by sorting the tuples by their first element, but keep track of the corresponding original values so that a list of the sorted original values could be created.

Let's repeat the previous example, but after having sorted the numbers by evenness, sort them in descending order within their group. This is known as secondary sort. This requires a neat trick that was mentioned in the Elixir documentation for this function. I can map the two sort values to a tuple and the default Elixir tuple comparison will cause the tuples to be ordered by the first element, and then by the second element if the first elements are equals That will allow me to specify values that will control the secondary sorting. I'll have to make the second value in the tuple negative to make the order descending instead of ascending.

iex> evenness_value = fn number -> rem(number, 2) end
#Function<6.99386804/1 in :erl_eval.expr/5>
iex> Enum.sort_by(1..10, &{evenness_value.(&1), -&1})
[10, 8, 6, 4, 2, 9, 7, 5, 3, 1]

That creates a list of tuples: {1, -1}, {0, -2}, {1, -3}, ..., which when sorted will produce the result I want.

Lovely. Now I'm going to demonstrate changing the sorter function. I'll map the values by "evenness" and then sort them in the opposite order by using the >=/2 function in the Kernel module for the sorter function. That will sort the numbers, putting the odd numbers before the even numbers.

iex> evenness_value = fn number -> rem(number, 2) end
#Function<6.99386804/1 in :erl_eval.expr/5>
iex> Enum.sort_by(1..10, &(evenness_value.(&1)), &>=/2)
[1, 3, 5, 7, 9, 2, 4, 6, 8, 10]]
iex> Enum.sort_by(1..10, &{evenness_value.(&1), &1}, &>=/2)
[9, 7, 5, 3, 1, 10, 8, 6, 4, 2]

I also used the tuple trick to then sort the values in descending order. There was no need to negate the second value in the tuple this time. The new sorter function will automatically sort in descending order.

After I've finished playing around with this function, I can see better how it might be useful. It might be easier to do certain kinds of sorting this way than just with a simpler comparison function. In fact, I rather like it. It's certainly less weird to me now that I've actually used it, and I can better envision how to use it.

There is definitely no equivalent to this function in Javascript and C#.

This was a bit difficult to figure out how to use, so I can understand it if my explanation doesn't make sense to you. If you do end up needing sort functionality that the other sort functions do not provide, I recommend re-reading this section, reading the documentation, and then playing around with the function to get a sense for how it works.

Enum.split/2

The Enum.split/2 function takes an enumerable and an integer "count" parameter. The enumerable is split into two lists, with the first list having the number of elements equal to the "count" parameter and the second list having all the remaining elements. Both lists are contained in a tuple.

If the "count" parameter is a positive number, then Enum.split/2 will take that many elements from the beginning of the enumerable. If the "count" parameter is a negative number, then Enum.split/2 will take that many elements from the end of the enumerable. The Elixir documentation notes that if a negative number is passed in, the function will perform two passes over the enumerable, the first one to find out how many elements there are and the second one to get the elements it needs.

I think of this function as being somewhat similar Enum.slice/3, where the slice is taken from the beginning or the end and the rest of the enumerable is put into another slice.

Here are some examples.

iex> Enum.split(1..10, 3)
{[1, 2, 3], [4, 5, 6, 7, 8, 9, 10]}
iex> Enum.split(1..10, -3)
{[1, 2, 3, 4, 5, 6, 7], '\b\t\n'}
iex> Enum.split(1..10, 15)
{[1, 2, 3, 4, 5, 6, 7, 8, 9, 10], []}
iex> Enum.split(1..10, 1)
{[1], [2, 3, 4, 5, 6, 7, 8, 9, 10]}
iex> Enum.split(1..10, 0)
{[], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]}

If a count is passed in that is larger than the enumerable, all the elements will be put into the first list and the second list will be empty. If a count of 0 is passed in, the first list will be empty and all the elements will be put into the second list.

There are no equivalent functions in Javascript or C#, although there are several functions (like slice() in Javascript or Take() in C#) that have some similarities.

Enum.split_while/2

The Enum.split_while/2 function is very similar to Enum.split/2 except that it does the splitting using a parameter function rather than using an index. The parameter function will be called for every element, and every element will be included in the first list while the function returns true. Once the function returns false, the current element and all the rest of the elements will be included in the second list.

Here are some examples.

#Define the is_even function
iex> is_even = &(rem(&1, 2) == 0)
#Function<6.99386804/1 in :erl_eval.expr/5>
#Split while the numbers are even numbers
iex> Enum.split_while([2, 4, 10, -2, 3, 8, -3, 12], is_even)
{[2, 4, 10, -2], [3, 8, -3, 12]}
#Split while the numbers are even numbers
iex> Enum.split_while(1..10, is_even)
{[], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]}
#Split while the numbers are less than 7
iex> Enum.split_while(1..10, &(&1 < 7))
{[1, 2, 3, 4, 5, 6], '\a\b\t\n'}
#Split while the square of the numbers are less than or equal to 20
iex> Enum.split_while(1..10, fn number -> (number * number) <= 20 end)
{[1, 2, 3, 4], [5, 6, 7, 8, 9, 10]}

There are no equivalent functions in Javascript or C#. However, the takeWhile() lodash function and the IEnumerable.TakeWhile() function in C# are very similar. Those functions, however, just return a single collection instead of two.

Enum.split_with/2

The Enum.split_with/2 splits the enumerable elements into two groups based on what the parameter function returns. Whereas Enum.split_while/2 uses the parameter function to tell it when to stop, Enum.split_with/2 runs over the entire enumerable and splits the elements based on what the parameter function returns. All elements for which the parameter function returns a truthy value are placed in the first list while all the elements for which the parameter function returns false are placed in the second list.

I've taken the examples from Enum.split_while/2 and replaced the function name with split_with. You will be able to see the difference between how these two functions work.

#Even numbers go in one list and odd numbers go in the other
iex> Enum.split_with([2, 4, 10, -2, 3, 8, -3, 12], is_even)
{[2, 4, 10, -2, 8, 12], [3, -3]}
#Even numbers go in one list and odd numbers go in the other
iex> Enum.split_with(1..10, is_even)
{[2, 4, 6, 8, 10], [1, 3, 5, 7, 9]}
#Numbers < 7 go in one list and numbers >= 7 go in the other
iex> Enum.split_with(1..10, &(&1 < 7))
{[1, 2, 3, 4, 5, 6], '\a\b\t\n'}
#Numbers whose squares <= 20 go in one list and numbers 
#whose squares > 20 go in the other
iex> Enum.split_with(1..10, fn number -> (number * number) <= 20 end)
{[1, 2, 3, 4], [5, 6, 7, 8, 9, 10]}

There are no equivalent functions in Javascript or C#, although there are functions with some similarities.

Enum.sum/1

The Enum.sum/1 function is the same thing that we were doing earlier in those reduce examples. It just sums up the numbers in a enumerable.

It only works on numbers (integer and floats), and it will throw an ArithmeticError if it encounters any non-numeric elements.

#Sum all numbers from 1 to 10
iex> Enum.sum(1..10)
55
#Sum a list with a single element
iex> Enum.sum([0])
0
#Sum all numbers from 1 to 1000
iex> Enum.sum(1..1000)
500500
#Sum a list with positive and negative numbers
iex> Enum.sum([-3, 0, 1, 2, 3, -4])
-1
#Sum a list with integers and floats
iex> Enum.sum([1, 2, 3, 3.14, 4.48, 5.1, 6])
24.72
#Sum an empty list
iex> Enum.sum([])
0
#Sum a list containing a non-numeric element
iex> Enum.sum([1, 2, "three", 4, 5])
** (ArithmeticError) bad argument in arithmetic expression: "three" + 3
    :erlang.+("three", 3)
    (elixir) lib/enum.ex:1925: Enum."-sum/1-lists^foldl/2-0-"/3

The Javascript lodash library has an equivalent function.

let numbers = [1, 2, 3, 4, 5];

//The result is 15
let result = _.sum(numbers);

The equivalent in C# is the LINQ extension function IEnumerable.Sum().

List<int> numbers = new List<int>() {1, 2, 3, 4, 5};

//The result is 15
int result = numbers.Sum();

Enum.take/2

The Enum.take/2 function takes the first N elements from the beginning of the enumerable or N elements from the end of the enumerable depending on whether N is positive or negative. This function works like Enum.split/2, except that only a single list is returned; the rest of the elements are discarded.

iex> Enum.take(1..10, 3)
[1, 2, 3]
iex> Enum.take(1..10, -3)
'\b\t\n'
iex> Enum.take(1..3, 5)
[1, 2, 3]
iex> Enum.take([], 5)
[]

Javascript does not have a native equivalent function, but lodash does: take() takes elements from the beginning of an array and takeRight() takes elements from the end of an array.

let numbers = [1, 2, 3, 4, 5];

//The result is [1, 2, 3]
let result = _.take(numbers, 3);

//The result is [3, 4, 5]
let result = _.takeRight(numbers, 3);

C# has IEnumerable.Take() and IEnumerable.TakeLast() in the LINQ extension methods.

List<int> numbers = new List<int>() {1, 2, 3, 4, 5);

//The result is {1, 2, 3}
List<int> result = numbers.Take(3).ToList();

//The result is {3, 4, 5};
result = numbers.TakeLast(3).ToList();

Enum.take_every/2

The Enum.take_every/2 function takes every Nth element from the enumerable, starting with the first element, and returns it in a list.

I think of this as the opposite of Enum.drop_every/2, which drops every Nth element and returns the rest.

Here are some examples.

#Take every third element starting with the first
iex> Enum.take_every(1..10, 3)
[1, 4, 7, 10]
#Take every second element starting with the first
iex> Enum.take_every(1..10, 2)
[1, 3, 5, 7, 9]
#Take every element
iex> Enum.take_every(1..10, 1)
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
#Passing a 0 as the second parameter will result in an empty list
iex> Enum.take_every(1..10, 0)
[]
#Negative numbers in the second parameter result in an error
iex> Enum.take_every(1..10, -1)
** (FunctionClauseError) no function clause matching in Enum.take_every/2

    The following arguments were given to Enum.take_every/2:

        # 1
        1..10

        # 2
        -1

    (elixir) lib/enum.ex:2490: Enum.take_every/2

Neither Javascript nor C# have an equivalent function.

Enum.take_random/2

The Enum.take_random/2 function takes N random elements from the enumerable, where N is a parameter that is passed in, and returns the elements in a list. This function is similar to Enum.random/1, except that it grabs multiple random elements instead of a single random element.

This is a fun function, and here are some examples of using it.

iex> Enum.take_random(1..100, 5)
[15, 21, 95, 58, 85]
iex> Enum.take_random(1..100, 5)
[75, 80, 21, 72, 57]
iex> Enum.take_random(1..100, 2)
'D5'
iex> Enum.take_random(1..100, 2)
'S='
iex> Enum.take_random(1..100, 1)
'L'

As usual, when we get a list of numbers in the printable character range, it is displayed as a character list.

Neither Javascript nor C# have an equivalent function.

Enum.take_while/2

The Enum.take_while/2 function takes elements from the beginning of the enumerable as long as the function passed to it returns a truthy value. Once the function returns a falsey value, the elements that were retrieved up to that point are returned in a list. This function is just like Enum.split_while/2, except that the rest of the enumerable is ignored.

iex> is_even = &(rem(&1, 2) == 0)
#Function<6.99386804/1 in :erl_eval.expr/5>
iex> Enum.take_while([-2, 0, 2, 4, 10, 6, 5, 10, 3], is_even)
[-2, 0, 2, 4, 10, 6]
iex> Enum.take_while([-2, 0, 9, 4, 10, 3], is_even)
[-2, 0]
iex> Enum.take_while(1..10, &(&1 < 8))
[1, 2, 3, 4, 5, 6, 7]

The Javascript library lodash has an equivalent function.

let numbers = [1, 2, 3, 4, 5];

//The result is [1, 2, 3]
let result = _.takeWhile(numbers, number => number < 4);

The equivalent in C# is the LINQ extension function IEnumerable.TakeWhile().

List<int> numbers = new List<int>() {1, 2, 3, 4, 5};

//The result is {1, 2, 3}
List<int> result = numbers.TakeWhile(number => number < 4);

Enum.to_list/1

The Enum.to_list/1 function puts the elements of an enumerable in a list and returns it. All it does is convert an enumerable to a list. That's not very useful if the enumerable is already a list, but it certainly is if the enumerable is something else.

iex> Enum.to_list(-2..2)
[-2, -1, 0, 1, 2]
iex> Enum.to_list([1, 2, 3])
[1, 2, 3]
iex> Enum.to_list(%{name: "Carlos", age: 3, location: :home})
[age: 3, location: :home, name: "Carlos"]

Since a map produces name-value tuples when it is enumerated, the result is a keyword list.

Since Javascript does not have a concept of enumerable types, there's nothing equivalent. C#, however, does have a method that converts an IEnumerable to a List<T>.

IEnumerable<int> range = Enumerable.Range(1, 5);

//The range is enumerated and result is {1, 2, 3, 4, 5}
List<int> rangeElements = range.ToList();

Enum.uniq/1

The Enum.uniq/1 function removes all the duplicate elements from an enumerable. Only the first element of a set of duplicates it encounters will be kept.

iex> Enum.uniq([1, 2, 3, 4, 5, 5, 6, 6, 6, 7, 7, 8, 9])
[1, 2, 3, 4, 5, 6, 7, 8, 9]
iex> Enum.uniq(["Bob", "Sam", "Mac", "Bob", "Mitt"])
["Bob", "Sam", "Mac", "Mitt"]
iex> Enum.uniq(1..10)
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

C# does not have an equivalent function, but the Javascript lodash library does.

let numbers = [1, 2, 2, 3, 4, 5, 4, 3, 2];

//The result is [1, 2, 3, 4, 5]
let uniqueNumbers = _.uniq(numbers);

Enum.uniq_by/2

The Enum.uniq_by/2 function works like Enum.uniq/1 except that it accepts a function that evaluates each element in the enumerable and returns a value. It's that value that is evaluated for uniqueness. This allows us to control what is a unique value.

Here's are some examples.

iex> is_even = &(rem(&1, 2) == 0)
#Function<6.99386804/1 in :erl_eval.expr/5>
iex> Enum.uniq_by(1..10, is_even)
[1, 2]
iex> Enum.uniq_by(["Bob", "Fuzz", "Sam", "Tim", "Zebediah", "Spam"], &String.length/1)
["Bob", "Fuzz", "Zebediah"]

In the first example, the function returns "evenness" of a number, so the only possible return values are true and false. So the first two elements are selected and the rest are ignored because the function returns duplicate values for those. In the second example, we convert strings to a number that corresponds to their length. The first string of a particular length is kept and the rest are discarded.

C# does not have an equivalent, but the Javascript lodash library does.

let names = ["Bob", "Fuzz", "Sam", "Tim", "Zebediah", "Spam"];

//The result is ["Bob", "Fuzz", "Zebediah"]
let uniqueLengths = _.uniqBy(names, name => name.length);

Enum.with_index/2

The Enum.with_index/2 function wraps each element from an enumerable in a tuple, where the first element is the enumerable and the second element is its index. I immediately saw the utility of this function. Many times have I wished that I had the current index available to me in the midst of an operation on an enumerable, such as a reduce operation. In such operations, you don't get the index by default, so you have to find some other way of getting it. In Elixir, you can convert the enumerable into a value-index tuple list and then perform an operation on that; the value and the index will be available.

The second parameter to Enum.with_index/2 specifies the index number to start from. This is an optional parameter, and it defaults to 0, which is the beginning of the enumerable. If you pass in a 2 for this parameter, the first element in the enumerable will be associated with 2, the second element with 3, etc.

Here are some examples.

iex> Enum.with_index(1..10)
[
  {1, 0},
  {2, 1},
  {3, 2},
  {4, 3},
  {5, 4},
  {6, 5},
  {7, 6},
  {8, 7},
  {9, 8},
  {10, 9}
]
iex> Enum.with_index(["a", "b", "c"])
[{"a", 0}, {"b", 1}, {"c", 2}]
#Start the indexes with 2 instead of 0
iex> Enum.with_index(["a", "b", "c", "d", "e"], 2)
[{"a", 2}, {"b", 3}, {"c", 4}, {"d", 5}, {"e", 6}]
iex> ["a", "b", "c"] |>
...> Enum.with_index() |>
...> Enum.reduce("", fn (tuple, combinedString) -> combinedString <> elem(tuple, 0)<> Integer.to_string(elem(tuple, 1)) end)
"a0b1c2"

In the last example, I piped the list ["a", "b", "c"] to Enum.with_index to get [{"a", 0}, {"b", 1}, {"c", 2}]. That was then piped to a call to Enum.reduce/3, which concatenated the letters and the indexes into a string, "a0b1c2".

Neither Javascript nor C# have an equivalent function.

Enum.zip/1

The Enum.zip/1 function receives a list of enumerables and zips them together. Zipping is the process of taking the first elements in each enumerable and combining them into a tuple. This is followed by a tuple of the second elements, a tuple of the third elements, and so forth until one of the enumerables runs out of elements. Those tuples are then returned in a list. This effectively "zips" the enumerables together into a single enumerable.

The zip operation will continue as long as at least all the enumerables still have elements available as they are being iterated over. When one (or more) of the enumerables runs out of elements, the elements remaining in the other enumerables are ignored.

Looking at some examples will be helpful.

iex> Enum.zip([[1, 2, 3], ["a", "b", "c"], [:one, :two, :three]])
[{1, "a", :one}, {2, "b", :two}, {3, "c", :three}]
iex> Enum.zip([[1, 2, 3], ["a", "b", "c"]])
[{1, "a"}, {2, "b"}, {3, "c"}]
iex> Enum.zip([1..10, 10..1])
[
  {1, 10},
  {2, 9},
  {3, 8},
  {4, 7},
  {5, 6},
  {6, 5},
  {7, 4},
  {8, 3},
  {9, 2},
  {10, 1}
]
iex> Enum.zip([1..10, 1..5])
[{1, 1}, {2, 2}, {3, 3}, {4, 4}, {5, 5}]

In the last example, the zipped list consists of only five tuples. This is because the shortest enumerable was only five elements long.

The Javascript lodash library has an equivalent function, _.zip().

let arrays = [[1, 2, 3, 4, 5], ["a", "b", "c"]];

//The result is [[1, "a"], [2, "b"], [3, "c"]]
let result = _.zip(arrays);

C# has an equivalent method in the LINQ extension methods that zips two enumerables together, IEnumerable.Zip(). It also requires a method parameter that indicates how the two elements will be zipped together.

List<int> numbers = new List<int>() {1, 2, 3, 4, 5};
List<string> letters = new List<string> {"a", "b", "c"};

//The result is {{1, "a"}, {2, "b"}, {3, "c"}}
List<Tuple<int, string>> result = numbers
	.Zip(letters, (number, letter) => Tuple.Create(number, letter))
	.ToList();

Enum.zip/2

The Enum.zip/2 function works just like Enum.zip/1 except it zips two enumerables together rather than a list of enumerables.

iex> Enum.zip(1..10, 1..5)
[{1, 1}, {2, 2}, {3, 3}, {4, 4}, {5, 5}]
iex> Enum.zip(1..5, ["a", "b", "c"])
[{1, "a"}, {2, "b"}, {3, "c"}]

Enum.unzip/1

The Enum.unzip/2 is the exact opposite of Enum.zip/2. It takes an enumerable consisting of two-element tuples and unzips the elements in the tuples, returning a tuple containing two lists. The first elements in the tuples are put in the first list and the second element in the tuples are placed in the second list.

This function only works if the enumerable passed into it is composed only of tuples and all tuples are two-element tuples.

#Unzip tuples of letters and numbers
iex> Enum.unzip([{1, "a"}, {2, "b"}, {3, "c"}])
{[1, 2, 3], ["a", "b", "c"]}
#Unzip tuples of numbers
iex> Enum.unzip([{1, 1}, {2, 2}, {3, 3}, {4, 4}])
{[1, 2, 3, 4], [1, 2, 3, 4]}
#This doesn't work because one of the tuples is not a two-element tuple
iex> Enum.unzip([{1, 1}, {2, 2}, {3, 3}, {4, 4, 5}])
** (FunctionClauseError) no function clause matching in anonymous fn/2 in Enum.unzip/1

    The following arguments were given to anonymous fn/2 in Enum.unzip/1:

        # 1
        {4, 4, 5}

        # 2
        {[3, 2, 1], [3, 2, 1]}

    (elixir) lib/enum.ex:2689: anonymous fn/2 in Enum.unzip/1
    (elixir) lib/enum.ex:1925: Enum."-unzip/1-lists^foldl/2-0-"/3
    (elixir) lib/enum.ex:1925: Enum.unzip/1
#This doesn't work because one of the elements is not a tuple
iex> Enum.unzip([{1, 1}, {2, 2}, {3, 3}, "a"])
** (FunctionClauseError) no function clause matching in anonymous fn/2 in Enum.unzip/1

    The following arguments were given to anonymous fn/2 in Enum.unzip/1:

        # 1
        "a"

        # 2
        {[3, 2, 1], [3, 2, 1]}

    (elixir) lib/enum.ex:2689: anonymous fn/2 in Enum.unzip/1
    (elixir) lib/enum.ex:1925: Enum."-unzip/1-lists^foldl/2-0-"/3
    (elixir) lib/enum.ex:1925: Enum.unzip/1
#This doesn't work because the tuples have three elements, and not two
iex> Enum.unzip([{1, 2, 3}, {4, 5, 6}])
** (FunctionClauseError) no function clause matching in anonymous fn/2 in Enum.unzip/1

    The following arguments were given to anonymous fn/2 in Enum.unzip/1:

        # 1
        {1, 2, 3}

        # 2
        {[], []}

    (elixir) lib/enum.ex:2689: anonymous fn/2 in Enum.unzip/1
    (elixir) lib/enum.ex:1925: Enum."-unzip/1-lists^foldl/2-0-"/3
    (elixir) lib/enum.ex:1925: Enum.unzip/1
#This doesn't work because the elements aren't tuples
iex> Enum.unzip(1..5)
** (FunctionClauseError) no function clause matching in anonymous fn/2 in Enum.unzip/1

    The following arguments were given to anonymous fn/2 in Enum.unzip/1:

        # 1
        1

        # 2
        {[], []}

    (elixir) lib/enum.ex:2689: anonymous fn/2 in Enum.unzip/1
    (elixir) lib/enum.ex:2967: Enum.reduce_range_inc/4
    (elixir) lib/enum.ex:1930: Enum.unzip/1

C# does not have an equivalent, but the Javascript lodash library does, _.unzip(). Unlike the Elixir version, there is no limit to the number of elements the sub-arrays can have.

let zippedArray = [[1, "a"], [2, "b"], [3, "c"]];

//The result is [[1, 2, 3], ["a", "b", "c"]]
let unzippedArray = _.unzip(zippedArray);

We've finally reached the end of the Enum module! That was a lot of functions, but I believe the Enum module is one of the most important modules in the Elixir standard library.