kodepett

kodepett

Is there a straightforward way of retrieving an element in this list [ {"server", "nginx"}, {"date", "Sat, 13 Nov 2021 18:25:48 GMT"}, {"content-type", "UTF-8"}, {"content-length", "23"}, {"freeflow", "FB"} ]

I’m afraid the ordering might change and hence can’t rely on elem . I’ve perused the doc and can’t find a straightforward of extracting individual fields using the first element(string) in the tuple as the key.

Showing Posts 1 to 10

thiagomajesk

thiagomajesk

If you can’t rely on the order I guess you’d have to use Enum.filter and friends.

PS: You could also transform this list into a map and use that map as a lookup.

mpope

mpope

If the elements are always tuples of two, I think you can use Keyword.get/3. Something like:

req =
  [ 
    {"server", "nginx"},
    {"date", "Sat, 13 Nov 2021 18:25:48 GMT"}, 
    {"content-type", "UTF-8"},
    {"content-length", "23"},
    {"freeflow", "FB"}
  ]
server = Keyword.get(req, "server")
krstfk

krstfk

Not necessarily the most efficient but should work (not tested) :

def get_elem([{key, v}| _tl], str) when key == str do
   {:ok, v}
end
def get_elem([_ | tl ], str), do: get_elem(tl, str)
def get_elem([], _str), do: :error_not_found

It’s also not necessarily the most idiomatic, Enum.find would be better.
Keyword won’t work since the first element of your tuple is a string and not an atom.

josevalim

josevalim

Creator of Elixir

Unfortunately Keyword expects the keys to be atoms. To lookup for any key, use List.keyfind/3 instead, such as:

List.keyfind(list, “server”, 0)

The above will look up on a list of tuples returning the first element where the position 0 of the tuple is the string ”server”.

kodepett

kodepett OP

Awesome, thank you.

krstfk

krstfk

TIL List.keyfind/3 is backed by a BIF. Nice, thanks.

eksperimental

eksperimental

Filter will return all the elements that have “server” as the first element of the tuple.

eksperimental

eksperimental

Just to illustrate another possibility,

You can use Enum.find/3 and Enum.find_value/3

iex> Enum.find_value(list, fn {"server", v} -> v; _ -> nil end)   
"nginx"

Enum.find_value is useful since you already know the key, you are probably interested in the value. Anyway I think it is more performant List.keyfind + pattern matching since it is a built-in internal function.

Another comment is that Elixir v1.13 is introducing List.keyfind!/3 you can read more about it here: List — Elixir v1.13.0-rc.0

krstfk

krstfk

I don’t want to hijack this topic, however the fact that List.keyfind/3 is backed by a bif got me curious.

I suspect, that this is because there’s no way to implement that function with arbitrary length tuples (should I say n-uples ?), and keys at arbitrary position, in pure Erlang, rather than raw speed considerations.

Benchmarking this leads to surprising results, on my machine with otp 24 with jit enabled:

defmodule Experiments do
  def get_elem(str, [{str, el} | _tl]) , do: el
  def get_elem(_str, []), do: :error_not_found
  def get_elem(str, [_ | tl]), do: get_elem(str, tl)

end

with

list = Enum.to_list(1..10_000_000)
tuples = Enum.map(list, fn el -> {"#{el}", "#{el}" } end)

Benchee.run(%{
  "get elem" => fn -> Experiments.get_elem("9999999", tuples) end,
  "keyfind" => fn -> List.keyfind(tuples, "9999999", 0) end,
}
)

gives the following result :

Operating System: macOS
CPU Information: Intel(R) Core(TM) i7-6700K CPU @ 4.00GHz
Number of Available Cores: 8
Available memory: 16 GB
Elixir 1.12.3
Erlang 24.1.2

Benchmark suite executing with the following configuration:
warmup: 2 s
time: 5 s
memory time: 0 ns
parallel: 1
inputs: none specified
Estimated total run time: 14 s

Benchmarking get elem...
Benchmarking keyfind...

Name               ips        average  deviation         median         99th %
get elem          7.31      136.76 ms     ±4.42%      134.81 ms      163.94 ms
keyfind           5.63      177.49 ms     ±6.72%      174.30 ms      234.07 ms

Comparison:
get elem          7.31
keyfind           5.63 - 1.30x slower +40.73 ms

That’s not to say one should use a custom function in that situation (as always, with performances, one should consider the input size, strike a balance between readability and gains, and benchmark if needed), it was just interesting.

josevalim

josevalim

Creator of Elixir

You can implement it using regular Elixir:

defmodule Experiments do
  def keyfind([head | tail], val, pos) when elem(head, pos) === val, do: head
  def keyfind([_ | tail], val, pos), do: keyfind(tail, val, pos)
  def keyfind([], _val, _pos), do: nil
end

Where Next? Top

Trending in Questions Top

katta
I having some trouble figuring out if I have set myself too strict of standards for my production server. Currently I can handle 75% of r...
New
peck
Hi everyone. My team and I have been working on a fairly modest app based around video streaming and chat, but we’ve landed a customer t...
New
achenet
Hello, I’m trying to build a basic Phoenix web-app, and I’d like to use Tailwind. However, when I launch mix phx.server, I get an error...
New
bradley
I really like the adapter patterns that ecto, nebulex, waffle, etc. use and would love find something similar for a key management servic...
New
unaware8150
Hello folks! So at work, we are seeing some situations where we have to define some “fixed” strings that are used across the codebase in...
New
Cxx-mlr
I’m working on a small exercise involving update_in/3, and I came up with this solution: data = %{ name: "Periodic Table", category:...
New
Alvinkariuki
How Can I Optimise Compile Time Dependencies I have been building an elixir application for about 2 years now. Many modules and files ha...
New

Other Trending Topics Top

budgie
A little off-topic, but I feel like people here have a good head on their shoulders. I used to be quite good at making software. Was luc...
New
KristerV
Hey. Is there anyone here who creates agents in their apps? Not talking about using agents, but creating them. I’m finding it pretty diff...
New
mudasobwa
I fully migrated to my own harness from Anthropic/Gemini and I think it’s time to share it. Welcome DSH, the DeepSeek Harness, fully writ...
New
jimsynz
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New
juhalehtonen
There has been a thread to discuss the Stack Overflow Developer Survey on this forum every year since 2018, so here’s yet another one for...
New
budgie
I love Elixir. It’s one of 2 programming languages I’ve ever fallen in love with. But I don’t use it anymore. Serverless was the promis...
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews