[TIL] How to check that a list has increasing values in Elixir

Dec 9 2019

I have been these days solving some of the problems of advent of code. These problems are a great way to sharpen your skills with any programming language. Although my preferred language is still Elixir, I am trying to improve a little of my Go knowledge so I decided to give a try solving these problems. Here there are the solutions that I wrote.

By the way, I have been reading some of the solutions in Elixir and some of them have impressed since they have shown new ways to face the problems. I will write down some of these techniques (New at least for me)

Traditional imperative paradigm

In a traditional imperative C-type language like is Go we can solve this with a simple loop like this (the snippet can be executed here):

package main

import "fmt"

func isIncreasingList(list []int) bool {
    for i:=0 ; i < len(list) - 1; i++{
        if list[i] > list[i + 1] {
            return false
        }
    }
    return true
}

func main() {
    list := []int{1, 2, 3, 4, 5}
    fmt.Printf("%+v IsIncreasing?: %t", list, isIncreasingList(list))
}

Functional Paradigm

In a functional language like Elixir this check can be quite more complicated. At first glance for me, one idea that comes into me mind was to build a list of tuples where each tuple contains one element and the his adjunt like [{i}, {i+1}]. For example:

# Having this list:
list = [1,2,3,4,5]
# The objective list would be this:
objective_list = [{1,2}, {2,3}, {3,4}, {4,5}]

We can get the objective_list doing this:

list = [1,2,3,4,5]
list1 = List.delete_at(list, length(list)-1)
list2 = List.delete_at(list, 0)
objective_list = Enum.zip(list1, list2)
> [{1, 2}, {2, 3}, {3, 4}, {4, 5}]

Once we have that list we can use Enum.all/2(), to evaluate if any of the tuples doesn't fullfil the requirement:

list = [1,2,3,4,5]
List.delete_at(list, length(list)-1)
|> Enum.zip(List.delete_at(list, 0))
|> Enum.all?(fn {v1, v2} -> v2 > v1 end)

This could seem like an easy way to get the problem done. But it could be even simpler there is an utility called Enum.chunk_every/4 that can help us in the process on separate in slices our list

Enum.chunk_every([1,2,3,4,5], 2, 1, :discard)
[[1, 2], [2, 3], [3, 4], [4, 5]]

Sorting everything up:

[1,2,3,4,5]
|> Enum.chunk_every(2, 1, :discard)
|> Enum.all?(fn {v1, v2} -> v2 > v1 end)

It is so amazing how some tedious problems in imperative languages can be solved in the functional paradigm. Maybe if we talk about performance probably the approximation of Go could be more efficient.