| Bytes | Lang | Time | Link |
|---|---|---|---|
| 021 | Pip xp | 220505T003641Z | DLosc |
| 029 | Bash sed + ShellShoccarjpn/Parsrs parsrj.sh | 221126T083030Z | 鳴神裁四点一号 |
| 088 | PowerShell Core | 220511T031605Z | Julian |
| 4011 | jq | 220504T232449Z | cnamejj |
| 073 | R | 220505T202628Z | Giuseppe |
| 036 | Perl 5 + M5.10.0 n0175 | 220505T195257Z | Dom Hast |
| 118 | Kotlin 1.6.21 | 220504T160624Z | Juuz |
| 014 | Jelly | 220503T181011Z | Jonathan |
| 067 | Perl 5 | 220503T170232Z | Kjetil S |
| 096 | Retina 0.8.2 | 220503T162952Z | Neil |
| 055 | JavaScript V8 | 220503T141721Z | Arnauld |
| 052 | Python | 220503T140550Z | pxeger |
Pip -xp, 23 21 bytes
FL:_.{b?'/.(\fb)x}MUa
Takes a list of tuples (i.e. two-element lists) as a command-line argument. Outputs a list of strings.
Explanation
A recursive full program:
FL:_.{b?'/.(\fb)x}MUa
a Program argument (a list of pairs)
MU Unpack and map this function to each pair:
_ The first element of the pair
.{ } Concatenated (itemwise if necessary) to:
b? Is the second element of the pair (a list) nonempty?
'/. If so, concatenate "/" (itemwise) to
(\f ) a recursive call of the main function
b with the second element of the pair as the argument
x If it is empty, empty string
FL: Flatten the resulting list
Bash (sed + ShellShoccar-jpn/Parsrs parsrj.sh), 31 29 bytes
Assumes parsrj.sh is on a directory specified by PATH environment variable.
Tested with parsrj.sh Version : 2020-05-06 22:42:19 JST.
parsrj.sh -rt -kd/|sed s,/$,,
Example runs on my Termux
Explained
parsrj.sh -rt -kd/|
# default output for {"foo":{"bar":{}},"baz":{}}:
# $.foo.bar.
# $.baz.
# -rt to replace $ with ""
# -kd/ to replace . with /
# thus output is:
# /foo/bar/
# /baz/
sed s,/$,,
# trailing slash is removed
PowerShell Core, 103 88 bytes
function f($o,$p){($x=$o.keys|%{f $o.$_ $p/$_})
if(!$x){$p}}f($args|ConvertFrom-Json -a)
Takes a string as a parameter
Returns a list of string with a leading /
Thanks mazzy for shaving 15 bytes off!
jq, 42 40 bytes (+11 penalty for "-r --stream" options)
select(.[1]=={})[0]|join("/")
The --stream option converts JSON to an alternate format where each leaf node is an element in a list. Those entries are also lists, with two fields, the first of which is a list of the keys representing the path. The second entry (for out test cases) is an empty dictionary.
So the code selects every list entry where the second entry is a an empty dictionary, them assembles the list of keys in the first entry into the output we want.
select(.[1]=={})[0] - pick "leaf" node entries only (1st field only)
|join("/") - join the list of string w/ a "/" separator
R, 79 73 bytes
f=function(L)"if"(length(L),unlist(Map(paste0,names(L),"/",Map(f,L))),"")
Takes input as a named R list, i.e., list(name=value), and returns a character (string) vector of directories.
-3 bytes thanks to pajonk.
Perl 5 + -M5.10.0 -n0175, 36 bytes
pop@;;push@;,/\w+/g;$,="/";/{/&&say@
Explanation
A different approach to the other Perl answer. This uses the -0175 command line flag to split the input on }. For each closing curly brace, @; is popped removing any previous path keys that aren't needed. Next all the keys (/\w+/g - this might be too lenient?) are pushed onto @;. Finally $, (which is printed between records when a list - @... - is printed) is set to "/" and if { exists in the input, say is used to output @; (with $, printed between each index).
Kotlin 1.6.21, 118 bytes
{fun f(m:Map<*,*>,s:(Any?)->Any){for((k,v)in m)if((v as Map<*,*>).size==0)s(k)else f(v){s("$k/$it")}};f(it,::println)}
An anonymous function of type (Map<*, *>) -> Unit that takes in a recursive map of String to Map<String, ...> and prints the answer without leading or trailing slashes.
Ungolfed code:
{
// Define function f that iterates a map recursively and
// outputs its keys' paths to a sink function
fun f(m: Map<*, *>, s: (Any?) -> Any) {
for ((k, v) in m)
// Note: .size==0 is 2 bytes shorter than .isEmpty()
if ((v as Map<*,*>).size == 0)
// For an empty map, call the sink with the key
s(k)
else
// Call f again on the inner map with a wrapped sink that
// that appends the current key + "/" to the input
f(v) { s("$k/$it") }
}
// Run f for the input map, using ::println as the sink
f(it, ::println)
}
Jelly, 14 bytes
;”/;ⱮßW⁹?}ʋ/€Ẏ
A monadic Link that accepts a list of lists where each is a key-value pair where the key is a list of characters and the value is a, possibly empty, list of the same type* and yields a list of lists of characters - the paths.
* i.e. uses the option a list or array of tuples, where each tuples contains the name/key and the value (which is itself a list of tuples).
How?
;”/;ⱮßW⁹?}ʋ/€Ẏ - (recursive) Link: list, J
€ - for each key-value pair in J:
/ - reduce by:
ʋ - last four links as a dyad - f(Key, Value)
”/ - '/' character
; - (Key) concatenate ('/')
} - use right argument, Value with:
? - if...
⁹ - ...condition: chain's right argument, Value
ß - ...then: call this recursive Link with that (non-empty) Value
W - ...else: wrap that (empty) Value in a list -> [[]]
Ɱ - map across the recursive call result (or the [[]]) with:
; - concatenate
Ẏ - tighten
Retina 0.8.2, 96 bytes
+1`"([^"]+)":{("[^"]+":{(({)|(?<-4>})|[^{}])*(?(4)^)},)*"(?!\1/)
$&$1/
M!`"[^"]+":{}
%`^.|....$
Try it online! Link includes test cases. Explanation:
+1`"([^"]+)":{("[^"]+":{(({)|(?<-4>})|[^{}])*(?(4)^)},)*"(?!\1/)
$&$1/
Replace each key in turn with its path.
M!`"[^"]+":{}
List the entries whose values are empty objects.
%`^.|....$
Keep just the keys.
JavaScript (V8), 55 bytes
Thanks to @pxeger for suggesting to use for(k in o)
Expects an object. Prints the results with a leading /.
f=(o,p,q)=>{for(k in o)f(o[q=k],[p]+'/'+k);q||print(p)}
JavaScript (V8), 63 bytes
Expects an object. Prints the results with a leading /.
f=(o,p)=>Object.keys(o).map(k=>f(o[k],[p]+'/'+k))+''||~print(p)
Python, 52 bytes
def f(d,s=""):[f(d[x],s+"/"+x)for x in d]or print(s)
Takes input as a dictionary, and outputs to STDOUT.
