Enum intersperse

Intersperse is the action of putting something in between other things.

In your Elixir application you might find yourself needing to output a string of comma separated names. You could do something like this as your first attempt but, this approach creates an extra comma and white space.


# Step 1
users = ["tony", "sam", "alex"]

# Step 2 - Add a comma to each name
list = for user <- users  do
   "#{user}" <> ", "
end

# Step 3 - Joinh into a string
Enum.join(list, "")

# "tony,  sam,  alex, "

What you want is the comma to appear in between the names. This is whereEnum.interprese/2 can help out.


# Step 1
users = ["tony", "sam", "alex"]
# ["tony", "sam", "alex"]

# Step 2 - Look at the commas within the list
list = Enum.intersperse(users, ", ")
# ["tony", ", ", "sam", ", ", "alex"]

# Step 3 - Join into a string
Enum.join(list, "")

# "tony, sam, alex"

This approach is much better. By using Enum.interprese/2 and Enum.join/2 you can achieve the result you were looking for.

However, our application is interactive and we need to get these names clickable. Let’s see how we can do this in a Phoenix application.

Real World Example

In my Phoenix application I have a list of users that need to be separated by a comma. Each user needs to be clickable but the comma needs to be plain text. In order to do this we are going to create a helper.

Create a shared_view.ex file within the views directory. This module is going to contain common functions that will be used across the application.


defmodule DemoWeb.SharedView do
  use DemoWeb, :view

  def linked_users(conn, users) do
    users
      |> Enum.map(fn(users) ->
        link(users.name, to: user_path(conn, :show, user.name), title: "See #{user.name} content")
      end)
      |> Enum.intersperse(", ")
  end

end

With DemoWeb.SharedView.linked_users/2 you pass in the current conn and the users. The function will then map through each user in the users list and apply the link/2 function to each user.

Once the map function has gone through the list, it returns a List containing HTML links. This list will then be passed into the Enum.interprese/2 as the first argument thanks to the |> and we pass in the ", " as the second argument. The result is we get an HTML presentation of links being separated by a comma.

Using the shared view

In my templates/shared directory I will use this as a template to render the list of users

<%= linked_users(@conn, @users) %>

In my Phoenix web app, I have a home page that shows some @users. So, I can now render the DemoWeb.SharedView module by calling that users.html and passing in the arguments as shown below

<section>
  <div class="container user-listing">
   <%= render DemoWeb.SharedView, "users.html", conn: @conn, users: @users %>
  </div>
</section>

Then my application should output HTML that looks something like this

  <section>
    <div class="container user-listing">
      <p>
        <a href="/user/tony" title="See tony content">tony</a>,
        <a href="/user/sam" title="See sam content">sam</a>,
        <a href="/user/alex" title="See alex content">alex</a>
      </p>
    </div>
  </section>