1. Fetching the default Mix Compilers list
iex> Mix.compilers
Returns the default compilers used by the Mix tool. The output will look
something similar to [:yecc, :leex, :erlang, :elixir, :xref, :app]
.
It can be used in your mix.exs
to prepend or append new compilers to Mix:
# mix.exs
def project do
[compilers: Mix.compilers ++ [:gettext]
end
2. Picking out the elements in List
We all know that a proper list is a combination of head and tail like [head | tail]
.
We can use the same principle for picking out the elements in the list like the following way…
iex> [first|[second|[third|[fourth|_rest ]]]]= [1,2,3,4,5,6,7]
[1, 2, 3, 4, 5, 6, 7]
iex> first
1
iex> {second,third,fourth}
{2, 3, 4}
# This is much better for picking elements
iex> [first,second, third, fourth | _rest]= [1,2,3,4,5,6,7]
You will get MatchError
Exceptoin if the Elements in the lists are
miss matched.
Match Error
no match of right hand side value: list
3. get_in /Acess.all()
We all know that the get_in
function is used to extract the key which
is deeper inside the map by providing the list with keys like a following way…
iex> user=%{"name"=>{"first_name"=>"blackode","last_name"=>"john" }}
%{"name" => %{"first_name" => "blackode", "last_name" => "john"}}
iex > get_in user,["name","first_name"]
"blackode"
But, if there is a list of maps [maps]
where you have to extract
first_name
from the each map, generally we go for Enum
. We can also
achieve this by using the get_in
and Access.all()
iex> users=
[
%{"user" => %{"first_name" => "john","age" => 23}},
%{"user" => %{"first_name" => "hari","age" => 22}},
%{"user" => %{"first_name" => "mahesh","age" => 21}}
]
# that is a list of maps
iex> get_in users, [Access.all(), "user", "age"]
[23, 22, 21]
iex> get_in users, [Access.all(), "user", "first_name"]
["john", "hari", "mahesh"]
🔥
If the key is not present in the map then it returns nil
Invalid Data Type
When you use the get_in
along with Access.all()
,
as the first value in the list of keys like above, the users datatype should be list.
If you pass the map
, it returns the error
.
iex> list = [%{name: "john"}, %{name: "mary"}, %{age: 34}]
[%{name: "john"}, %{name: "mary"}, %{age: 34}]
iex> get_in(list, [Access.all(), :name])
["john", "mary", nil]
Did you observe that in the above lines of code, the key name
is missing in some of the maps.
So, it returns nil
for key which is not in the map
.
iex> get_in(%{name: "blackode"}, [Access.all(), :name])
If you execute above line you will get the following error
Runtime Error
Access.all/0 expected a list, got: %{name: "blackode"}
(elixir) lib/access.ex:567: Access.all/3
Hope you observed that it is raising error while you try to pass the map
instead of a list
.
However, you can change the position of the Access.all()
in the list.
But the before key
should return a list
.
Deep Dive
We can also use the Access.all()
with functions like update_in
, get_and_update_in
, etc…
For instance, given a user with a list of books, here is how to deeply traverse the map and convert all book names to uppercase:
iex> user =
%{ name: "john",
books: [
%{name: "my soul",type: "tragedy"},
%{name: "my heart", type: "romantic"},
%{name: "my enemy", type: "horror"}
]
}
iex> update_in user, [:books, Access.all(), :name], &String.upcase/1
%{
books: [
%{name: "MY SOUL", type: "tragedy"},
%{
name: "MY HEART",
type: "romantic"
},
%{name: "MY ENEMY", type: "horror"}
],
name: "john"
}
iex> get_in user, [:books, Access.all(), :name]
["my soul", "my heart", "my enemy"]
Here, user
is not a list
unlike in the previous examples where we passed the users
as a list
.
But, we changed the position of Access.all()
and inside the list of keys
[:books, Access.all(), :name]
, the value of the key :books
should return
the list
, other wise it raises an error
.
4 . Data Comprehension along with filters
We achieve the data comprehension through for x <- [1,2,3],do: x+1
.
But, we can also add the comprehension along with filter.
General usage
iex> for x <- [1,2,3,4], do: x+1
[2,3,4,5]
# this is how we use in general lets think out of the box
With filters
Here, I am using two lists of numbers and cross product over the lists and
filtering out the product which is a odd number
.
iex> for x <- [1,2,3,4], y <- [5,6,7,8], rem(x*y, 2) == 1 do
{x, y, x*y}
end
[
{1, 5, 5},
{1, 7, 7},
{3, 5, 15},
{3, 7, 21}
]
#here rem(x*y,2)==1 is acting as a filter
5. Comprehension with binary strings
Comprehension with binary is little different. You supposed to wrap inside <<>>
Lets check that…
iex> b_string = <<"blackode">>
"blackode"
iex> for << x <- b_string >>, do: x+1
'cmbdlpef'
Here, I am just printing out the letter after every letter in the “blackode”
Did you observe that x <- b_string
is just changed something like << x <- b_string >>
to make the sense.
6. Advanced Comprehension IO.stream
Here, we are taking the Elixir
comprehension to the next level.
🔥 We read the input from the keyboard and convert that to upcase and after that it should wait for another entry.
for x <- IO.stream(:stdio,:line),
into: IO.stream(:stdio, :line),
do: String.upcase(x)
Basically, IO.stream(:stdio,:line)
will the read a line input from the keyboard.
iex(10)> for x <- IO.stream(:stdio,:line),into: IO.stream(:stdio, :line), do: String.upcase(x)
hello
HELLO
hi
HI
who are you?
WHO ARE YOU?
blackode
BLACKODE
^c ^c # to break
7. Single Line Multiple module aliasing
We can also alias
multiple modules in one line:
alias Hello.{One,Two,Three}#The above line is same as the following alias Hello.One alias Hello.Two alias Hello.Three
8. Importing Underscore Functions
By default the functions with _
are not imported. However, you can do that by
importing them with :only
explicitly.
import File.Stream, only: [__build__: 3]
9. Sub string in Elixir
There is no direct sub_str
function in elixir. However, you can get that by
String.slice/2
iex> String.slice("blackode", 1..-1)
"lackode"
iex> String.slice("blackode", 0..-4)
"black"
10. String Concatenation
We can do the string concatenation in two ways.
iex> str1 = "hello"
iex> str2 = "blackode"
I am taking above lines of code for using in examples.
String Interpolation
iex> mystring = "#{str1}#{str2}"
helloblackode
Using <> operator
iex> mystring = str1 <> str2
helloblackode
This is the best style and recommended one.
If you are having the list of strings ["hello","blackode"]
then use Enum.join
iex> mystrings=["hello","blackode"]
["hello","blackode"]
iex> mystrings |> Enum.join
"helloblackode"
Check out the GitHub repository on Killer Elixir Tips
Glad if you can contribute with a ★