Can I send the result from 2 functions to the same function and if so how?

I am having an issue where I don’t know how to pass 2 lists from 2 different functions(fun1 and fun2) to one function(fun3) in a way where it uses both of them at the same time. I think the issue is the pattern matching, I don’t know how to format the individual lists to where fun3 can accept them at the same time. I am trying to stick to best practices using more smaller functions but do I need to just combine these functions so I can send them at the same time? Yes, I am a noobie so be kind oh elixir gods and goddesses.

Fun1

def videoFilePurifier(videoList), do: doVideoFilePurifier(videoList, [])

   defp doVideoFilePurifier([], vFlaggedList) do
     flaggedListFormatter(_, vFlaggedList)
   end
   defp doVideoFilePurifier([head | tail], vFlaggedList) do
     if String.contains?(head, @extensionList) do
       doVideoFilePurifier(tail, vFlaggedList)
     else
       vFlaggedList = List.insert_at(vFlaggedList, 0, head)
       doVideoFilePurifier(tail, vFlaggedList)
     end
   end

Fun2

def nonVideoFilePurifier(nonVideoList), do: doNonVideoFilePurifier(nonVideoList, [])

   defp doNonVideoFilePurifier([], nvFlaggedList) do
     flaggedListFormatter(nvFlaggedList, _)
   end
   defp doNonVideoFilePurifier([head | tail], nvFlaggedList) do
     if String.contains?(head, @extensionList) do
       nvFlaggedList = List.insert_at(nvFlaggedList, 0, head)
       doNonVideoFilePurifier(tail, nvFlaggedList)
     else
       doNonVideoFilePurifier(tail, nvFlaggedList)
     end
   end

Fun3

 def flaggedListFormatter(nvFlaggedList, vFlaggedList) do
     flaggedList = nvFlaggedList ++ vFlaggedList
     doFlaggedListFormattter(flaggedList, %{})
   end

     defp doFlaggedListFormatter([], flaggedMap), do: IO.puts(flaggedMap)
     defp doFlaggedListFormatter([head | tail], flaggedMap) do
       fileName = Path.basename(head)
       Map.put(flaggedMap, fileName, head)
       doFlaggedListFormatter(tail, flaggedMap)

     end

If I understand correctly, the intention is:

  1. filter the list of video files
  2. filter the list of non-video files
  3. merge and format filtered out “flagged” lists into a map
    If so then, the way I see functions are written, I think, you jump to call flaggedListFormatter too quickly.

Instead, in your code, I think, the base case of both doVideoFilePurifier/2 and doNonVideoFilePurifier/2 could return just a flaggedList and then we run flaggedListFormatter/2 on them:

def videoFilePurifier(videoList), do: doVideoFilePurifier(videoList, [])

defp doVideoFilePurifier([], vFlaggedList), do: vFlaggedList
defp doVideoFilePurifier([head | tail], vFlaggedList) do
  ...
end

def nonVideoFilePurifier(nonVideoList), do: doNonVideoFilePurifier(nonVideoList, [])

defp doNonVideoFilePurifier([], nvFlaggedList), do: nvFlaggedList
defp doNonVideoFilePurifier([head | tail], nvFlaggedList) do
  ...
end

# usage
v_flagged_list = videoFilePurifier(video_list)
nv_flagged_list = nonVideoFilePurifier(non_video_list)

flaggedListFormatter(v_flagged_list, nv_flagged_list)

BTW, in elixir we use snake_case Naming Conventions — Elixir v1.13.1

1 Like

Much appreciated on the snake case I’ll change that, any advice like that is very appreciated. I want it to work best so if I just sent them through individually how would I go about having a map that collects all of the flagged file paths that I send through and keep them? Would it naturally just keep all of the flagged file paths until I run all of the lists through?

Sorry, I didn’t get the question. It would help if you provide with the simplified examples of inputs and desired outputs, what you are getting now and what’s wrong.

So the function recursively works through a directory and all its subdirectories looking for videos in non-video folders and non-video files in video folders. The goal is to accept a path and output a map with all of the flagged files found inside that directory.

Here is the GitHub erovf/erovf.ex at master · TinyBFG/erovf · GitHub
(Just cuz I really don’t know all the info you might need)

Again any and all criticism/advice appreciated and thank you for your patience

Yes. It will. It is what we call an accumulator.
It is the way to keep state in functional programming. You keep passing it on from function to function.

what do you mean by _, as that is invalid code in Elixir

I think I sort of see what you mean.
Please share how you call these functions.

That’s the thing is that it doesn’t get passed through the whole function but I might have to reorganize this module to just make a giant map and eliminate things from it as I go.

I would call them by passing a path through the 1st function then they would get called as the directory is worked through. I would check GitHub if you want to see the whole thing.erovf/erovf.ex at master · TinyBFG/erovf · GitHub

1 Like

yes.
for example here.

the results from videoFilePurifier(video_list) are lost. you are just burning computer cycles doing nothing. (unless your videFilePruifier/1 has sideefect such as storing the results to a file a something).

what you can do is merge boths lists and return the result, such as doing (this example will just joining them keeping duplicates if they are keyword lists)

videoFilePurifier(video_list) ++ nonVideoFilePurifier(non_video_list)

I don’t know how big your directories, or how long it will take to process them.
You can always save your temporary results to a .beam file in Erlang native code and later retrieve them with :erlang.term_to_binary and :erlang.binary_to_term

1 Like

Oh my gosh, thank you so much! I have been staring and poking at this thing for a while knowing it was probably a simple fix like this. You are awesome!

1 Like
@spec nonVideoFilePurifier(List) :: List, List

Here is something that is wrong. You cannot return 2 lists like that,
if you want to do that you need to return {list1, list2} since in Elixir functions return only one term.

so your spec should look like

@spec nonVideoFilePurifier(list()) :: {list(), list()}

I would recommend you to run mix format in your project.

Once you get more acquainted with the language, see if you can install dialyxirso you can run mix dialyzer and it will warn you about all this, but as of it could be too advanced for your level the output of dialyzer.

2 Likes

No worries. We have all been there. You probably are still carrying an imperative-language-baggage, that you will eventually let go.

3 Likes

I would also like to point out that here you update the accumulator map but do not bind the updated value to a new variable, so you can pass the updated map to the next fuction call. Results will always be the original empty map. You can do a rebinding like flagged_map = Map.put(flagged_map, file_name, head)

2 Likes

https://github.com/TinyBFG/erovf/blob/1e0c466af0ac999f15d3a1c842946ae9f21b5894/lib/erovf.ex#L233

Use IO.inspect to inspect anything that is may not be converted to a string. if your list contains for example a range, it iwill raise with IO.puts.

While IO.inspect and IO.puts returns the value of the term, I would consider it bad practice for them to be the last evaluated expression.

Instead of

  defp doFlaggedListFormatter([], flagged_map), do: IO.puts(flagged_map)

you can do

  defp doFlaggedListFormatter([], flagged_map) do
     IO.inspect(flagged_map)
     flagged_map
 end

and whenever you finish debugging, you comment out the IO.inspect, and comment it back when you need to see what is going on.

IO.puts always returns :ok by the way.

1 Like

Just want to give a general thank you to all you guys who commented. I know it was probably a rough read and I want to make sure you guys know you’re appreciated! Thanks a ton!

I love this community!

3 Likes