Extract Multiple Values with Enum.map?

Hello all!

Curious how to iterate with Enum.map and return multiple values from a set of data.

For example, lets say i want location, daysofweek, starttime, endtime.

My code for finding location looks like-

def get_data do
    url = "https://data.sfgov.org/resource/jjew-r69b.json?"
    response = HTTPoison.get!(url)
    body = Poison.decode!(response.body, keys: :atoms)

    body
    |> Enum.map(& &1.location)
    |> Enum.join(", ")
  end

I think there might be a more elegant way to do a few values in one go and create a new struct? Perhaps Enum.map is the wrong way to go for my desired use case.

Looking like a for comprehension might be my best bet?

Thanks for any help!

Perhaps what you want is Map.take/2?
We can still combine it with Enum.map/2

    body
    |> Enum.map(&Map.take(&1, [:location, :daysofweek, :starttime, :endtime])
    ...

I would say it depends on what you want to do with that data later and whether or not you want to handle possible missing keys.

This works and is a good start! Thanks Rud :yellow_heart:

Definitely. Could do some pattern matching to handle missing values down the line.

Well, if you use pattern matching within a list comprehension (for %{a: a, b: b} <- data, do: <something>) you will drop every item that does not fit, whereas Map.take/2 will leave you with more or less what you already have, just with less keys in the maps. Comprehensions also have a convenient :reduce option for whatever you might want to do later.

Again, I know nothing about the API or your requirements towards it, so I’m just thinking out loud about things to keep in mind :slight_smile:

2 Likes

Can you show us what the end result should look like? I’m not sure if what you want is a list of strings or one enormously big string.

1 Like

Also, it looks like you’re discarding the atoms of the API call return after using them to access the fields of the maps. Atoms are never garbage collected on the BEAM platform which Elixir runs on, so I’d recommend just using plain strings for both performance and security. The general rule of thumb here is to only generate atoms at compile time.

List of strings for sure. Ah I was unaware of that best practice for atoms!

“down the line”?

Bruh, that’s literally 5 more minutes of work. :003: Come on now.

1 Like

B b b but I’m just building an MVP :rofl:.

You got me Dimitar :pray:

Yeah so if you want a list of strings where each string goes like “location, daysofweek, starttime, endtime” then you could try something like this:

get_values = fn map, keys -> for k <- keys, do: map[k] end
keys_to_get = ["location", "daysofweek", "starttime", "endtime"]
for item <- body, do: Enum.join(get_values.(item, keys_to_get), ", ")
1 Like

That makes sense! I’m wondering now how to display this information in a sensible format on a LiveView page. Even with the comma separation after Enum.join it’s still a wall of text! I’ve tried a few different ideas with "\n" and the like but am a bit stumped.

Tables work well for tabular data :wink:. I’m not a web dev and don’t know anything about LV/Phoenix but I guess I’d look into some simple HTML+CSS, should go well enough.