shashi / FileTrees.jl

Parallel computing with a tree of files metaphor
http://shashi.biz/FileTrees.jl
Other
88 stars 6 forks source link

Expand files into multiple new ones #51

Open jkrumbiegel opened 3 years ago

jkrumbiegel commented 3 years ago

I couldn't quite figure out how to do this: I have a bunch of audio files and want to do four transformations on each of them, resulting in four separate files per original file. I don't think I can map over the files and return multiple new files each, or maybe that works with mapsubtrees? I'm not sure

DrChainsaw commented 3 years ago

If you return a new FileTree it will be appended to the matching for both map and mapsubtrees. The function maketree can be useful for this, but one can also call the FileTree constructor as is.

Example with the former:


julia> ft= maketree(["a" => [(name="b", value=1), (name="c", value=2)]])
./
└─ a/
   ├─ b (Int64)
   └─ c (Int64)

julia> mapsubtrees(ft, r"b") do node
       return ft
       end
./
└─ a/
   ├─ a/
   │  ├─ b (Int64)
   │  └─ c (Int64)
   └─ c (Int64)
``´
jkrumbiegel commented 3 years ago

In my case this didn't quite work because I don't want to replace a File with a FileTree of one folder with four files, but basically just with the four files in the same folder that the file was in. This currently adds a "./" node which I guess can cause problems when using glob patterns etc? I understand why it happens, but it would be cool if the "same level" tree could be flattened.

MWE:

julia> tree = maketree(["folder" => [(name = "file", value = "value")]])
./      
└─ folder/
   └─ file (5-codeunit String)

julia> map(tree, dirs = false) do file
    maketree([(name = "file $i", value = i) for i in 1:4])
end
./      
└─ folder/
   └─ ./
      ├─ file 1 (Int64)
      ├─ file 2 (Int64)
      ├─ file 3 (Int64)
      └─ file 4 (Int64)
DrChainsaw commented 3 years ago

Hi,

You can specify the name of the root of you put is as the very first argument (note that the array starts at after the => )

julia> newtree = map(tree, dirs = false) do file
           maketree(name(file) => [(name = "file $i", value = i) for i in 1:4])
           end
./
└─ folder/ 
   └─ file/
      ├─ file 1 (Int64)
      ├─ file 2 (Int64)
      ├─ file 3 (Int64)
      └─ file 4 (Int64)

If you don't want the file intermediate level I think you need to rewrite the map so it maps all nodes and then replace "folder" instead of "file". Alternatively, you can just mv after:

julia> mv(newtree, r"file/", s"")
./
└─ folder/
   ├─ file 1 (Int64)
   ├─ file 2 (Int64)
   ├─ file 3 (Int64)
   └─ file 4 (Int64)
DrChainsaw commented 3 years ago

Fwiw, here is the function I use in my own code to do this in one go. As you can tell from the name and usage, it requires one to think a bit carefully when using it:

julia> mapleavesparent(f, ft) = map(ft) do node
       # NOTE: Only applies when all children are files. What does the user want to do if there is a mix of Files and FileTrees?
       eltype(children(node)) === File ? f(node) : node
end;

julia> mapleavesparent(tree) do node
         # Just don't forget that "file" is the child of node, not node itself
         maketree(name(node) => [(name = "file $i", value = i) for i in 1:4])
       end
./
└─ folder/
   ├─ file 1 (Int64)
   ├─ file 2 (Int64)
   ├─ file 3 (Int64)
   └─ file 4 (Int64)
shashi commented 3 years ago

I think

./      
└─ folder/
   └─ ./
      ├─ file 1 (Int64)
      ├─ file 2 (Int64)
      ├─ file 3 (Int64)
      └─ file 4 (Int64)

Should behave equivalently to

./      
└─ folder/
      ├─ file 1 (Int64)
      ├─ file 2 (Int64)
      ├─ file 3 (Int64)
      └─ file 4 (Int64)

Or maybe there should be a function which turns the former into the latter.