Reputation: 3140
{status, body} = File.read("/etc/hosts")
if status == :ok do
hosts = String.split body, "\n"
hosts = Enum.map(hosts, fn(host) -> line_to_host(host) end)
else
IO.puts "error reading: /etc/hosts"
end
I have the following elixir function where I read the /etc/hosts file and try to split it line by line using String.split
.
Then I map through the line list of hosts and call line_to_host(host) for each. The line_to_host method splits the line by " "
and then I want to set the from
and to
variable:
def line_to_host(line) do
data = String.split line, " "
from = elem(data, 0) // doesn't work
to = elem(data, 1) // doesn't work either
%Host{from: from, to: to}
end
I looked through stackoverflow, the elixir docs and googled about how to get an list element at a specific index.
I know there is head/tail
but there has to be a better way of getting list elements.
elem(list, index)
does exactly what I need but unfortunately it's not working with String.split
.
How to get list/tuple elements by ID in elixir
Upvotes: 49
Views: 49313
Reputation: 1146
You can consider implementing a recursive function instead Enum.at. It would provide more performance. It depends on if you need a high-performance code, of course.
Benchmarking:
Comparison:
Recursive Enum At 9.41 M
Native Enum At 6.48 M - 1.45x slower +48.05 ns
Example code:
defmodule Test do
def enum_at([h | t] = x, i) when i > 0 do
enum_at(t, i-1)
end
def enum_at([h | t], i), do: h
end
#[1,2,3,4,5,6,7,8] |> Test.enum_at(4)
# 5
In your case:
data = String.split line, " "
%Host{from: enum_at(data, 0), to: enum_at(data, 1)}
Pattern Matching could be the best option, but it could "fail" if the split returns a 3 elements list. You should add validations on both cases.
Upvotes: 2
Reputation: 54674
You can use pattern matching for that:
[from, to] = String.split line, " "
Maybe you want to add parts: 2
option to ensure you will get only two parts in case there is more than one space in the line:
[from, to] = String.split line, " ", parts: 2
There is also Enum.at/3
, which would work fine here but is unidiomatic. The problem with Enum.at
is that due to the list implementation in Elixir, it needs to traverse the entire list up to the requested index so it can be very inefficient for large lists.
Edit: here's the requested example with Enum.at
, but I would not use it in this case
parts = String.split line, " "
from = Enum.at(parts, 0)
to = Enum.at(parts, 1)
Upvotes: 53