64

I'm trying to convert a struct to a map to be able to clean all the nil values

I'm currently using this code

 case Nadia.get_updates do {:ok, results} -> Map.from_struct(results) |> Enum.filter(fn {_, v} -> v != nil end) |> Enum.into(%{}) 

Note: Nadia.get_updates returns the following structure: https://hexdocs.pm/nadia/Nadia.Model.Update.html#t:t/0

Yet I'm always receiving the following error: no function clause matching in Map.from_struct/1

1
  • 6
    Maybe results is a list of these structs? Not only one struct? Commented Apr 9, 2016 at 4:58

4 Answers 4

129

Since v0.15 we have Map.from_struct/1 which does exactly this.

defmodule User do defstruct [:name] end Map.from_struct(%User{name: "valim"}) #=> %{name: "valim"} 
Sign up to request clarification or add additional context in comments.

1 Comment

Haha! Judging by the upvote I've been here before... perhaps I should get a tattoo :)
17

There's another trick

my_struct = %MyStruct{} my_map = Map.delete my_struct, :__struct__ 

3 Comments

mymap = Map.delete(mystruct, :__meta__) |> Map.delete(:__struct__)
@nelsonic - I actually like the approach that Juliano suggested Map.from_struct(%User{name: "valim"}) is better way to do that
Yeah, Map.from_struct/1 is definitely good for regular structs. But when the struct is an Ecto changeset Map.from_struct/1 won't fully work so we need: mymap = Map.from_struct(changeset) |> Map.delete(:__meta__)
2
get_updates([{atom, any}]) :: {:ok, [Nadia.Model.Update.t]} | {:error, Nadia.Model.Error.t} 

If successful it returns a list of Nadia.Model.Update.t. That's why you get that error.

Comments

1

FWIW, I wrote a library that will do this kind of thing for you automagically w/o having to pull the data structure apart.

https://github.com/philosophers-stone/transform

This is from the test code:

test "implement scrub of empty values from map" do data = %{ :a => nil, :b => "", :c => "a"} replace_empty = fn(string, _d) -> if( string == "", do: nil , else: string) end replace_nil = fn(map, _depth) -> for {k, v} <- map, v != nil , into: %{}, do: {k, v} end potion = %{ BitString => replace_empty, Map => replace_nil} assert PhStTransform.transform(data, potion) == %{:c => "a"} end 

Note, if data was a list of maps this would still work just fine. The PhStTransform library will just keep pulling the data apart until it finds a map. In your case you would use a replace_nil function that worked on the kinds of structs you are interested in.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.