Formatting Lists of Maps

I’ve a data source that’s returning some time series data that I’d like to ultimately chart in Phoenix. However I’m having some trouble massaging it into some format or another that I can use.

What I’m starting with is along the lines of:

[
  %{x: 1570117280000, y: 16},
  %{x: 1570117288000, y: 16},
  %{x: 1570117296000, y: 16},
  %{x: 1570117304000, y: 16}
]

I’ve been able to render a graph by doing:

stats
|> Enum.map(&Map.to_list/1)
|> Enum.map(&Keyword.values/1)
|> Jason.encode!()

And then passing it through the controller to the template, which gives me:

[  
  [1570117280000, 16],
  [1570117288000, 16],
  [1570117296000, 16],
  [1570117304000, 16]
]

But I’m struggling with how to format the key values. For example, converting the unix timestamp x to something more friendly.

How do I manipulate a specific key’s value when I’m going through the list?

I don’t see keys in your final list, what result do You expect to have?

Sorry, all the charting libs I’ve looked at seem to expect value lists minus the key attributes which was why I passed it through Enum.map(&Keyword.values/1) in order to strip those out.

The bit I’m failing to understand is how I would parse/format a key value prior to that step. For example, going from:
[ %{x: 1570117280000, y: 16}, %{...} ]
to
[ %{x: "Thursday, 3 October 2019 15:41:20", y: 16}, %{...} ]

I know I can do something like Timex.from_unix(1570117280000, :millisecond) which will give me a datetime e.g. ~U[2019-10-03 15:41:20.000Z] but I don’t know the syntax to select the key while enumerating through the list and applying a specific operation against the value.

I hope that makes sense.

Is this what you’re looking for?

[
  %{x: 1570117280000, y: 16},
  %{x: 1570117288000, y: 16},
  %{x: 1570117296000, y: 16},
  %{x: 1570117304000, y: 16}
]
|> Enum.map(fn(%{x: x, y: y}) -> [DateTime.from_unix!(x, :millisecond), y] end)
|> Jason.encode!()
3 Likes

Enum.map

1 Like

Perfect! Thanks @albydarned.

This is probably a stupid question but why does the new map structure go inside square brackets?

It is how You represented the result in the first post… and it is not a map, but a list.

An alternative…

iex> list = [
  %{x: 1570117280000, y: 16},
  %{x: 1570117288000, y: 16},
  %{x: 1570117296000, y: 16},
  %{x: 1570117304000, y: 16}
]
iex> Enum.map(list, &Map.put(&1, :x, DateTime.from_unix!(&1.x, :millisecond)))
[
  %{x: ~U[2019-10-03 15:41:20.000Z], y: 16},
  %{x: ~U[2019-10-03 15:41:28.000Z], y: 16},
  %{x: ~U[2019-10-03 15:41:36.000Z], y: 16},
  %{x: ~U[2019-10-03 15:41:44.000Z], y: 16}
]

# or this classy one

iex> Enum.map(list, & %{&1 | x: DateTime.from_unix!(&1.x, :millisecond)})  
3 Likes