How to repeat the same method with different arguments a dynamic amount of times

I am new to Elixir and I can’t manage to wrap my head around it and find a solution. Basically I have a struct made out of strings and I have a method which replaces placeholders within the struct values by using a tuple, an example of a string value would be: “Hello ${name}!” with the tuple {“name”, “world”} would print out: Hello world!. That’s basically how it should work (just to set the idea).

Now I managed to make my code work and replace the placeholders, but I hardcoded it, so only specific placeholders can be replaced. I used regex to find all placeholders and list them so it’s not a problem to dynamically find them.

Here comes the problem:

I need to call a method for every placeholder there is and get the updated value and call it again on it until all of the placeholders are called and get the end result of the struct. The following code made sense in my head initially because of my previous knowledge of C type languages:

struct = # do some methods to get the initial value

Enum.each placeholders, fn({placeholder, data}) ->
  struct = StructModule.replace(struct, placeholder, data)
end

I mean I guess you could see the general idea which I have here. But, again, as Elixir is an immutable language I do get the data variable on the left hand side of the equation sign but on the next call it is forgotten. I guess it can’t reassign the value of the scope one level above?

It’d be a great help if anyone could link me somewhere where I could find a solution!

Hi Zastrix,

If I am getting the problem right, I think the best way to solve it would be to use a reducer. The problem is that with each call, you reassign what is in struct, but the code actually uses the initial struct instead of the one computed on the previous call.

So I believe it could be something similar to:

initial_struct = # do some methods to get the initial value

Enum.reduce placeholders, initial_struct, fn({placeholder, data}, acc) ->
  StructModule.replace(acc, placeholder, data)
end

I do think that should work. Maybe I got the syntax wrong. If you like you can check the reduce documentation here: https://hexdocs.pm/elixir/Enum.html#reduce/3

3 Likes

Yes, Enum.reduce is the way to go…

But I would like to highlight some things about FP

There are no methods, but functions

It looks like a procedural loop, with no return value where You want mutate struct.

Using Enum.reduce will reduce an enumerable into the struct accumulator. Enum is probably the most used module and worth learning it’s functions.

Welcome to forum and to FP :slight_smile:

2 Likes
defmodule Demo do
  def replace(data, template),
    do: List.foldl(data, template, &replace_holder/2)

  defp replace_holder({name, value}, template),
    do: String.replace(template, "##{name}", value)
end

template = "#greeting #name!"

data = [
  {"greeting", "Hello"},
  {"name", "world"}
]

IO.inspect(Demo.replace(data, template))
$ elixir demo.exs
"Hello world!"
$ 

Thank you for telling me which term was correct to use!

I heard that Enum is the most used module and figured that the answer was there, I just couldn’t pinpoint it.

Thanks, this is exactly what I needed! Somehow I managed to skip over the function documentation, many thanks!

1 Like

Glad to hear it was what you were looking for. Welcome to Elixir Forum. Yes, Enum is the most used module, it will let you do a lot of things.