aalberti333

aalberti333

Enum.map over list of key/value pairs with a map as the value

As the title describes, I’m trying to run Enum.map() over a list of key/value pairs, where the value is a map. My data looks like this:

[
        {"2015-02-23",
        %{
          "1. open" => "94.6226",
          "2. high" => "95.0000",
          "3. low" => "94.1250",
          "4. close" => "94.3130",
          "5. volume" => "19943800"
        }},
        ...
]

and I’ve tried the following with no success:

def datestr_to_datetime(ticker_map) do
    ticker_map
    |> Enum.map(fn {k, {nk, nv}} -> {Date.from_iso8601!(k), {nk, Float.parse(nv)}} end)
    |> Enum.sort_by(fn {d, v} -> {{d.year, d.month, d.day}, v} end)
end

this fails at Enum.map, and I’m not sure why. Any help is greatly appreciated!

Marked As Solved

al2o3cr

al2o3cr

A good general practice when writing data transformations is “align the shape of code with the shape of the data it processes”. In this case, your requirement starts with “a list of key-value pairs”, so write the corresponding code:

def convert_from_strings(data) do
  Enum.map(data, &convert_one_element/1)
end

def convert_one_element({key_string, stats_map}) do
  # TODO: return {new_key, new_stats_map}
  {key_string, stats_map}
end

Your next requirement: the incoming key should be converted from a string to a date with Date.from_iso8601!/1. convert_from_strings will stay the same for a while, since we’ve focused attention down to one element.

def convert_one_element({key_string, stats_map}) do
  {
    Date.from_iso8601!(key_string),
    stats_map
  }
end

Your next requirement: each value in stats_map should be converted with Float.parse/1. We can write that function first:

def convert_stats_map(stats_map) do
  stats_map
  |> Enum.map(fn {k, v} -> {k, convert_float(v)} end)
  |> Map.new()
end

def convert_float(string_value) do
  string_value
  |> Float.parse()
  |> elem(0)
end

and then hook it up:

def convert_one_element({key_string, stats_map}) do
  {
    Date.from_iso8601!(key_string),
    convert_stats_map(stats_map)
  }
end

Last requirement: the list should be sorted by year/month/day. This changes convert_from_strings, giving the final code:

def convert_from_strings(data) do
  data
  |> Enum.map(&convert_one_element/1)
  |> Enum.sort_by(fn {d, v} -> {{d.year, d.month, d.day}, v} end)
end

def convert_one_element({key_string, stats_map}) do
  {
    Date.from_iso8601!(key_string),
    convert_stats_map(stats_map)
  }
end

def convert_stats_map(stats_map) do
  stats_map
  |> Enum.map(fn {k, v} -> {k, convert_float(v)} end)
  |> Map.new()
end

def convert_float(string_value) do
  string_value
  |> Float.parse()
  |> elem(0)
end

Some notes:

  • to completely match the structure, there should be a convert_key_string function called from convert_one_element. All it would do is call Date.from_iso8601!, so I wrote it inline.

  • consider making most of these convert_* functions private

  • the Access protocol and the associated functions in Kernel can DRY up some of this quite a bit:

def convert_from_strings_with_access(data) do
  import Access

  data
  |> update_in([all(), elem(0)], &Date.from_iso8601!/1)
  |> update_in([all(), elem(1)], &convert_stats_map/1)
  |> Enum.sort_by(fn {d, v} -> {{d.year, d.month, d.day}, v} end)
end

Sadly there’s no equivalent of Access.all() for “every value in a Map”, or this wouldn’t need convert_stats_map even.

Also Liked

hauleth

hauleth

Just to let you know:

enumerable
|> Enum.map(&fun/1)
|> Map.new()

Is less idiomatic than:

enumarable
|> Map.new(&fun/1)
hauleth

hauleth

How do you think it would work? It try to match:

        {"2015-02-23",
        %{
          "1. open" => "94.6226",
          "2. high" => "95.0000",
          "3. low" => "94.1250",
          "4. close" => "94.3130",
          "5. volume" => "19943800"
        }}

to

{k, {nk, nv}}

But 2nd value in tuple is map() but you try to match it to 2-ary tuple.

Where Next?

Popular in Questions Top

chokchit
** (DBConnection.ConnectionError) connection not available and request was dropped from queue after 2733ms. You can configure how long re...
New
siddhant3030
Hi, I have to write a raw query for one of my project. But till now I have used ecto queries and don’t have much experience writing raw ...
New
mcarvalho
What is the difference between System.get_env and Application.get_env? For example, what are best practices to use one versus another.
New
johnnyicon
Hi all, I've just started learning Elixir and Phoenix Framework, so please pardon my n00bness at this stage. I'm trying to use Postg...
New
vrod
I am using the Starship cross-shell prompt – it seems pretty nice, but I get some errors: [WARN] - (starship::utils): Executing command ...
New
nobody
How to bind a phoenix app to a specific ip address? could not find anything about that, nowhere, unfortunately, but for me this is qui...
New
lucidguppy
I have a super simple question about elixir - how would I take a file like this foo bar baz and output a new file that enumerates th...
New
romenigld
I am trying to run a deploy with docker and I successfully runned with this command: docker build -t romenigld/blog-prod . but when I t...
New
joaquinalcerro
Hi there, I am working with Ecto-Postgresql and I need to call all of the records from a specific table but the table has 40,000 record...
New
lanycrost
Hi everyone! I need implement if…else if…else condition from my elixir code, and anymore of this control flow structures not work proper...
New

Other popular topics Top

Darmani72
If I have a post route which an argument: post /my_post_route/:my_param1, MyController.my_post_handler How would get the post params ...
New
msaraiva
Surface is an experimental library built on top of Phoenix LiveView and its new LiveComponent API that aims to provide a more declarative...
564 43591 214
New
joeerl
Hello again - after a longish gap I’ve decided I really must dig into Elixir and see what’s been happening here - so I have a few questio...
New
aalberti333
As the title describes, I’m trying to run Enum.map() over a list of key/value pairs, where the value is a map. My data looks like this: ...
New
chrismccord
This release brings a number of exciting features, including integration with the new Phoenix LiveDashboard and Phoenix LiveView. There h...
New
hariharasudhan94
lets say i have a sample like a = 20; b = 10; if (a > b) do {:ok, "a"} end if (a < b) do {:ok, b} end if (a == b) do {:ok, "eq...
New
rms.mrcs
Hi, I need to transform a list of numbers into a map where the keys are the indexes and the values are the original values of the list....
New
shijith.k
I am trying to start a new phoenix project with elixir 1.9, but mix phx.new does not work. It says that ** (Mix) The task "phx.new" could...
New
Qqwy
Update: How to use the Blogs & Podcasts section You can post links to your blog posts or podcasts either in one of the Official Blog...
3271 126226 1237
New
jononomo
For some reason my phoenix channels are working for me in my local dev environment, but as soon as I deploy via Docker, I get a 403 error...
New

We're in Beta

About us Mission Statement