afhuertass

afhuertass

Traverse nested list and if the list has two elements apply function

Hi!

I have been dealing with some problem where I have a nested list, I want to keep the nested structure, but if the list is a two elements list, then i want to apply a custom function (I’m dealing with multypolygon coordinates and want to apply some transform to the coordinates’ system)

So far, I came up with something using recursion:

defmodule NiceModule do
  def apply_function(nested_list) do
    update_in(nested_list, [Access.all()], fn item ->
      case item do
        [x, y] when is_number(x) and is_number(y) -> fun_fun(x, y)  
        sublist when is_list(sublist) -> apply_function(sublist)  
        other -> other  
      end
    end)
  end
  def fun_fun(x,y) do
    {a,b} ={ x+3 , y+2}
    [a,b]
  end
end

aa = [
  [2, 5.0 , [ 1 , 1 ]],
  [[13.0, 17.0], [25.0, 0.0], [0, 0]] ,
  [ 2 ,2 ]
]

NiceModule.apply_function(aa)

Which I think works, but I’m wondering if I’m doing something anti-elixir or if there is a better way (needless to say, I’m new)

Thanks for your time and answers :slight_smile:

Most Liked

Eiji

Eiji

If that’s all you need then why not simply use Enum.map/2 instead?

    Enum.map(nested_list, fn
      [x, y] when is_number(x) and is_number(y) -> fun_fun(x, y)  
      sublist when is_list(sublist) -> apply_function(sublist)  
      other -> other  
    end)

Creating a tuple that is not needed is just waste of time and resources.

defmodule NiceModule do
  def apply_function(nested_list) do
    Enum.map(nested_list, fn
      [x, y] when is_number(x) and is_number(y) -> [x + 3, y + 2]
      sublist when is_list(sublist) -> apply_function(sublist)  
      other -> other  
    end)
  end
end

This code is 40% (6 of 16 LOC) shorter and therefore definitely more readable.

Eiji

Eiji

Both of course are valid - they are equivalents in this example. Enum.map/1 is just much simpler here. You use update_in/3 together with Access.all/0 in case you have to update a nested (non-recursive) structure, for example:

defmodule NiceModule do
  def apply_function(map_with_nested_list) do
    update_in(map_with_nested_list, [:aa, Access.all()], &do_apply_function/1)
  end

  defp do_apply_function([x, y]) when is_number(x) and is_number(y), do: [x + 3, y + 2]
  # Pay attention that apply_function/1 call here was changed to do_apply_function1
  defp do_apply_function(sublist) when is_list(sublist), do: do_apply_function(sublist)  
  defp do_apply_function(other), do: other 
end

map = %{
  # aa in your example becomes a key in map
  aa: [
    [2, 5.0 , [ 1 , 1 ]],
    [[13.0, 17.0], [25.0, 0.0], [0, 0]] ,
    [ 2 ,2 ]
  ]
}

NiceModule.apply_function(map)

However if in above example we may use the value of a map key as same as sublist, so we can use Map.update!/3 instead.

defmodule NiceModule do
  def apply_function(map_with_nested_list) do
    Map.update!(map_with_nested_list, :aa, fn
      # the difference is that specified map value can be a list with 2 numbers (not nested)
      [x, y] when is_number(x) and is_number(y) -> [x + 3, y + 2]
      sublist when is_list(sublist) -> apply_function(sublist)
      # similar case here - we allow everything else as a map value
      other -> other  
    end)
  end
end

but nested data does not need to be that simple (nested list or map with nested list), but be more complex. Simply try to find the API that do what you expect in simplest form.

In your example you did not support root list to not be nested or be something else as the item variable is the item in the root list and not the root list itself. To do same in my first example we would need to move pattern-matching to apply_function/1 definition, for example:

defmodule NiceModule do
  # the difference is that specified map value can be a list with 2 numbers (not nested)
  def apply_function([x, y]) when is_number(x) and is_number(y), do: [x + 3, y + 2]
  def apply_function(sublist) when is_list(sublist), do: Enum.map(sublist, &apply_function/1)  
  # similar case here - we allow everything else as a map value
  def apply_function(other), do: other 
end
al2o3cr

al2o3cr

+1 for the other suggestion about using Enum.map if you’re doing a simple “loop over every element in a list”

Another small nitpick: if you’re representing coordinates, an {x, y} tuple would usually be preferred over a two-element list [x, y]. It’s very slightly more space-efficient, and very very very slightly faster to access y.

That could also make your recursion simpler, since then the rule is “if it’s a tuple, transform it; otherwise recurse”.

Where Next?

Popular in Questions Top

Tee
can someone please explain to me how Enum.reduce works with maps
New
lessless
I believe there are people here who are dealing with CSV files import on the daily basis, and since Excel is a really popular tool there ...
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
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
mgjohns61585
Could someone help me? I'm making my first elixir program, number guessing game. I can't figure out how to convert the user's guess from ...
New
aadeshere1
I have a another noob question about loop. Since elixir is immutable, while loop is not directly possible. total = 10 while total != 0 ...
New
shahryarjb
Hello, I have map which I want to convert it to string like this: the map: %{last_name: "tavakkoli", name: "shahryar"} the string I ne...
New
kostonstyle
Hi all I want to have a unix time, from the current time plus 1 hour. DateTime.now + 1 hour How to get it in elixir? Thanks
New
WestKeys
Currently suffering from paralysis by [HTTP client] analysis. This is rather unusual in Elixirland as there tends to be consensus on the ...
New
Codball
Mix format works fine if run from the cmd. I’ve followed this to facilitate the implementation into VSC which involves downloading an ext...
New

Other popular topics Top

Brian
What is the proper way to load a module from a file in to IEX? In the python world, doing something like this pretty standard: from ....
New
chrismccord
Phoenix 1.4.0 released Phoenix 1.4 is out! This release ships with exciting new features, most notably with HTTP2 support, improved deve...
688 30048 115
New
William
I would like to know that is there any online source for learning Phoenix Framework for building E-Commerce Store? Any advantage on build...
New
KronicDeth
Elixir plugin for JetBrain’s IntelliJ Platform (including Rubymine) This is a plugin that adds support for Elixir to JetBrains IntelliJ...
289 35421 110
New
SoCreat
i’m a new one to elixir which editor can i use vs code? or atom? Thanks! :smiley:
New
polypush135
As many of you may have realized by now (sorry for all the posts here) I’ve been working on a db problem where I’m trying to aggregate a ...
New
lk-geimfari
What is most correct way to open, read and parse JSON file with poison? For example if we have example.json file in root of some projec...
New
chrismccord
As promised, the first release candidate of Phoenix 1.3.0 is out! This release focuses on code generators with improved project structure...
New
ovidiubadita
Hey all, I discovered Elixir and I love it. I always wanted to learn a functional programming and I intended to go for Haskell, but afte...
New
AstonJ
We’ve put together this wiki for Phoenix LiveView - please feel free to add any info you feel is worth including. What is Phoenix LiveV...
New

We're in Beta

About us Mission Statement