Elixir Comprehensions - The "for" macro
In this post we will be going over comprehensions in Elixir. A “Comprehension” is another word for Elixir’s for macro. It can be used to iterate through an enumerable, like Enum or Stream:
for element <- Enumerable do
element
end
In Elixir, it is common to loop over an Enumerable. Often times we would want to filter out some results and map the values into another list.
Comprehensions are what allow us to achieve this goal.
Let's look at this example where we map a list of integers into their squared values:
for n <- [1, 2, 3, 4], do: n * n
[1, 4, 9, 16]
The "for" macro consists of three parts:
- Generators
- Filters
- Collectables (The :into Option)
Enum vs. Stream vs. for
Generators
Generators are written like this:
element <- Enumerable
In the expression below, n <- [1, 2, 3, 4]
is the generator. It is literally generating values to be used in the comprehension. Any enumerable can be passed on the right-hand side of the generator expression:
for n <- 1..4, do: n * n
[1, 4, 9, 16]
You can use multiple generators in a single for comprehension. Here is an example of this:
suits = [:hearts, :diamonds, :clubs, :spades]
faces = [2, 3, 4, 5, 6, 7, 8, 9, 10,
:jack, :queen, :king, :ace]
for suit <- suits,
face <- faces,
do: {suit, face}
Generators also support pattern matching on their left-hand side. Non-matching patterns get ignored.
Imagine that instead of a range, we have a keyword list where the key is the atom :good or :bad and we only want to compute the square of the :good values:
values = [good: 1, good: 2, bad: 3, good: 4]
for {:good, n} <- values, do: n * n
[1, 4, 16]
Filters
Alternatively to pattern matching, filters can be used to select some particular elements. Filter expressions are written after generators like this:
for element <- Enumerable, filter do
element
end
For example, we can select the multiples of 3 and discard the rest:
multiple_of_3? = fn(n) -> rem(n, 3) == 0 end
for n <- 0..5, multiple_of_3?.(n), do: n * n
[0, 9]
Comprehensions discard all elements for which the filter expression returns false or nil. All other values are selected.
Like generators, you can also use multiple filters:
for {suit, face} <- deck,
suit == :spades,
is_number(face),
face > 5,
do: {suit, face}
Comprehensions generally provide us with a much more concise representation than using the equivalent functions from the Enum
and Stream
modules.
:into
In the examples above, all the comprehensions returned lists as their result. But, the result of a comprehension can be inserted into different data structures by passing the :into
option to the comprehension.
Return something other than a list with the :into option:
for {key, val} <- %{name: "Daniel", dob: 1991, email: "..."},
key in [:name, :email],
into: %{},
do: {key, val}
The above use case of :into is transforming values in a map, without touching the keys.
Let’s make another example below using streams. Fire up your IEx shell and insert the code below into it.
Since the IO module provides streams, an echo terminal that echoes back the upcased version of whatever is typed can be implemented using comprehensions:
stream = IO.stream(:stdio, :line)
for line <- stream, into: stream do
String.upcase(line) <> "\n"
end
Now type any string into the terminal and you will see that the same value will be printed in upper-case.
uniq: true
can also be given to comprehensions to guarantee the results are only added to the collection if they were not returned before. For example:
for x <- [1, 1, 2, 3], uniq: true, do: x * 2
[2, 4, 6]
Note: The targets must support the Collectable protocol.
Variable Scoping
All variables used in for
are locally scoped:
name = "Nolan"
for name <- names do
String.upcase(name)
end
name # => "NOLAN"
Hi! I am a robot. I just upvoted you! I found similar content that readers might be interested in:
https://elixir-lang.org/getting-started/comprehensions.html
Hello again. Thanks for sharing this in the Programming community. While I won't be trying it at the moment, I'd love to see what you come up with!
It is plagiarism. Please check the Hivewatchers source in te comment below (this post was edited later).
Hi there,
I did look at the post history and I understand where you are coming from. The text portion of the post is quite similar to that of the documentation (and could've been lifted - which I wouldn't approve) but I like to err on the safe side and I've written reports about computing concepts (for college) with over 25% "plagerised" text because some concepts can't be explained in a different way. I would like to see this content improve. I weighted it myself off of the fact that he had understood it (so it seems, I can't write elixr) and provided unique examples (yes the first example is the same as the documentation I am aware).
I hope we can come to a reasonable understanding together, if you think I'm talking out of my ass and it is plagerised, that's a fair opinion to have. I'm just talking from my perspective.
Many thanks,
~ CA
Hi,
As you see in post history, this user edited parts after being caught.
"if you think I'm talking out of my ass and it is plagerised"
Not at all :-)
When I looked at plagiarism in this post, I also took into account copypasta/plagiarism found in 2 other posts published by this user. This suggested that it was not a one-off mistake.
Hello again,
I have now taken some time to look at previous posts, and I must admit your argument is pretty convincing. I even found this post about the enum module that seems to co-incide a lot with Nolyoi's Post. The uniswap post isn't even code related and looks like a pretty like-for like copy with some words removed.
I am going to see about getting the OCD vote removed and then I will hide this post within the community.
Many thanks for the help,
~ CA
Source
Plagiarism is the copying & pasting of others' work without giving credit to the original author or artist. Plagiarized posts are considered fraud and violate the intellectual property rights of the original creator.
Fraud is discouraged by the community and may result in the account being Blacklisted.
If you believe this comment is in error, please contact us in #appeals in Discord.
How is it fraud to mix in examples from a documentation? I even linked the documentation in the post several times lol. Good job.
Congratulations @nolyoi! You have completed the following achievement on the Hive blockchain and have been rewarded with new badge(s) :
You can view your badges on your board and compare yourself to others in the Ranking
If you no longer want to receive notifications, reply to this comment with the word
STOP
Do not miss the last post from @hivebuzz:
@hivewatchers @themarkymark
How am I on a blacklist for posting 1 post against your rules? I don't see how I even broke the rules. I used some examples from the Elixir docs as well as some of my own examples that I made. Then added some of my own descriptions of things. AND I linked to the sources of the examples.
https://blacklist.usehive.com/user/nolyoi