| Bytes | Lang | Time | Link |
|---|---|---|---|
| 099 | PHP | 211003T161237Z | LucianDe |
| 256 | Go | 240614T142922Z | bigyihsu |
| 057 | Julia 1.0 | 211006T162012Z | MarcMush |
| 092 | Ruby | 191108T030623Z | Value In |
| 075 | JavaScript Node.js | 191108T045052Z | tsh |
| 027 | Wolfram Language Mathematica | 191108T221506Z | LegionMa |
| 114 | R | 191108T173926Z | Nick Ken |
| 072 | JavaScript V8 | 191108T081953Z | Arnauld |
| 159 | Red | 191108T091622Z | Galen Iv |
| 119 | Python 2 | 191108T062742Z | Chas Bro |
PHP, 147, 146, 145, 120, 99 bytes
function f($a,$t=''){foreach($a as$k=>$v){$t1=$t?"$t.$k":$k;echo"$t1\n";!is_array($v)?:f($v,$t1);}}
/** Assume decoded json */
$array = json_decode('{
"name" : {
"first": "jane",
"last": "doe"
},
"lang" : [
"html",
"css"
]
}', true);
formatArrayKeys($array);
/**
* Extract all multidimensional array keys.
* The result will be as:
* - firstKey
* - firstKey.firstSubKey
* - firstKey.firstSubKey.firstSubSubKey
* - firstKey.secondSubKey
* - secondKey
* - etc.
*/
function formatArrayKeys($array, $acc = ''){
foreach($array as $key => $value) {
$newAcc = $acc ? "$acc.$key" : $key;
echo "$newAcc\n";
!is_array($value) ?: formatArrayKeys($value, $newAcc);
}
}
Go, 256 bytes
import."fmt"
func w(l string,j map[string]any)(a[]string){S:=Sprintf
for k,v:=range j{q:=k
if l!=""{q=S("%s.%s",l,q)}
a=append(a,q)
switch v:=v.(type){case []any:for i:=range v{a=append(a,S("%s.%d",q,i))}
case map[string]any:a=append(a,w(q,v)...)}}
return}
Takes a parsed JSON object as a map[string]any and the initial key, which starts as "", as input.
Explanation
import."fmt"
func w(l string,j map[string]any)(a[]string){
S:=Sprintf
for k,v:=range j{ // for each key and value pair...
q:=k;if l!=""{q=S("%s.%s",l,q)} // if the starting key is not empty; i.e. not at top level, append it to the current key
a=append(a,q) // add to the output
switch v:=v.(type){ // switch on the value type, where...
case []any:for i:=range v{a=append(a,S("%s.%d",q,i))} // an array has each index added
case map[string]any:a=append(a,w(q,v)...)}} // a nested object recurses
// otherwise do nothing
return}
Ruby, 108 146 115 92 bytes
+38 bytes to fix test cases for objects inside arrays.....
-31 bytes because we can take a parsed JSON object as input now.
-17 bytes by removing the duplicated flat_map usage.
f=->j,x=''{z=j==[*j]?[*0...j.size]:j.keys rescue[];z.flat_map{|k|[r=x+k.to_s]+f[j[k],r+?.]}}
JavaScript (Node.js), 75 bytes
f=o=>Object.keys(o+''===o||o||0).flatMap(k=>[k,...f(o[k]).map(i=>k+'.'+i)])
Wolfram Language (Mathematica), 39 27 bytes
MapIndexed[Echo@#2&,#,∞]&
Try it online! This function represents JSON arrays as Lists and objects as Associations. The function takes a JSON object as input and prints a set of part specifications to the standard output, each on their own line and preceded by >> . A part specification is a list of indices, where each index is a 1-based number or a string wrapped in Key. The index of a parent object is printed after those of its children. The output for the first example is:
>> {Key[name], Key[first]}
>> {Key[name], Key[last]}
>> {Key[name]}
>> {Key[lang], 1}
>> {Key[lang], 2}
>> {Key[lang]}
If the Key wrapper is undesirable, it can be removed using a 36-byte function:
Wolfram Language (Mathematica), 36 bytes
MapIndexed[Echo[#2/.Key->N]&,#,∞]&
The original challenge's formatting can be achieved with a 54-byte function:
Wolfram Language (Mathematica), 54 bytes
MapIndexed[Print@StringRiffle[#2/.Key->N,"."]&,#,∞]&
R, 114 bytes
f=function(x){if(is.null(n<-names(x)))n<-seq(x);unlist(Map(function(y,z)c(z,if(is.list(y))paste(z,f(y))),x,n),,F)}
Defines a recursive function which takes an R list, possibly named, and returns the list of names using space as a separator. Here, a named list (or sub list) corresponds to an object in JSON, and an unnamed list corresponds to an array in JSON.
JavaScript (V8), 72 bytes
An edited version to support literal false, true and null values.
f=(o,s)=>!o|[o]==o||Object.keys(o).map(k=>f(o[k],k=s?s+[,k]:k,print(k)))
JavaScript (V8), 69 bytes
Takes a native JSON object as input. Prints the results, using a comma as the delimiter.
f=(o,s)=>[o]==o||Object.keys(o).map(k=>f(o[k],k=s?s+[,k]:k,print(k)))
How?
This is a recursive function walking through the keys at the root level and then in each sub-tree of the structure.
We need to process recursive calls on objects and arrays and to stop on strings and numbers. This is achieved with [o]==o||Object.keys(o):
type of o | [o]==o | Object.keys(o) | string coercion example
-----------+-----------+-----------------+-------------------------------------
array | false | 0-based indices | ['foo', 'bar'] -> 'foo,bar'
object | false | native keys | {abc: 'xyz'} -> '[object Object]'
string | true | n/a | 'hello' -> 'hello'
number | true | n/a | 123 -> '123'
Red, 159 bytes
func[s][r: :rejoin g: func[s m][foreach k keys-of m[print p:
r[s k]if map? t: m/:k[g r[p"."]t]if block? t[repeat n length?
t[print r[p"."n]]]]]g ""load-json s]
Doesn't work in TIO since load-json was introduced recently, but works fine in the Red console:

Python 2, 122 135 122 119 bytes
f=lambda d:`d`[0]in'{['and sum([[str(k)]+['%s.'%k+q for q in f(v)]for k,v in(enumerate,dict.items)['{'<`d`](d)],[])or[]
Now handles an even broader class of inputs, including lists of dicts.