Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

flatten example does not flatten arrays #349

Open
samer1977 opened this issue May 24, 2024 · 1 comment
Open

flatten example does not flatten arrays #349

samer1977 opened this issue May 24, 2024 · 1 comment

Comments

@samer1977
Copy link

Hi,
I noticed the flatten-objects function here doesnt flatten nested arrays. I understand that flattening can have different meaning & expectations depending on each use case but my expectation when I want to flatten a json that it should cover everything. Of course considering arrays can get very complex given what arrays can hold. Part of learning jslt I wanted to take on this challenge to see if it can be done. I hope I was successful but part of doing this I found myself using some other helpful functions (see comments on each function) that I thought it might be nice to have not just for flattening but for other things and maybe have them as built function. Without further due , here is the code:

// This is different way of zipping where the key is the index itself. I found that provide more direct way if you need to access the index
// vs storing the index in another key.
def zip-by-index(json)
  
  let res = if(is-array($json)) [for(zip-with-index($json)) {string(.index):.value}] else []
  $res

//This is to make an array as complex object to create uniformity on how complex types in json can be processed. Im not sure there are 
// many use cases for this but its nice to have as an option
def objectify-array(array)
 let res = if($array==[] or $array==null) {}
          else if(size($array)==1) $array[0]
          else $array[-1]+objectify-array($array[0 : -1])
 $res 

def flatten_json(prefix,json)

   let simple=  {for($json) $prefix+.key:.value if(.key!=null and not(is-object(.value)) and not(is-array(.value)))}
   let complex= [for($json)  flatten_json($prefix+.key+".",.value) if(is-object(.value))]
   let array= [for($json)  flatten_json($prefix+.key+".",objectify-array(zip-by-index(.value))) if(is-array(.value))]
   
   objectify-array($array)+objectify-array($complex)+$simple
    

flatten_json("",.)

Example:

{
  "x": "x1",
  "y": "y2",
  "z": {
    "z1": "z11",
    "z2": null,
    "z3": [
      1,
      {
        "zzz": "skid",
        "zzz1": null
      },
      2
    ]
  }
}

Output:

{
  "x" : "x1",
  "y" : "y2",
  "z.z1" : "z11",
  "z.z3.0" : 1,
  "z.z3.2" : 2,
  "z.z3.1.zzz" : "skid"
}

I appreciate any well explained feedback.
Thanks
S

@catull
Copy link

catull commented May 28, 2024

This is not my original code, I stole it from here.

I changed it very lightly, it is not exactly what you want, because it does not process arrays, yet.
See the unchanged z3 array below.

At any rate, here it is:

// JSLT transform which flattens nested objects into flat objects
// { "a": { "b": 1 } } => { "a.b": 1 }
def flatten-object (obj)
  let flat = { for ($obj) .key : .value if (not (is-object (.value))) }

  let nested = [
     for ($obj)
     let outerkey = (.key)
       [for (flatten-object (array (.value))) {
         "key": $outerkey + "." + .key,
         "value": if (is-object (.value)) flatten-object (.value) else .value
       }]
     if (is-object (.value))
  ]

  let flattened = (flatten ($nested))

  { for ($flattened) .key : .value } + $flat

flatten-object (.)

This transformation produces for the input above this result:

{
  "x" : "x1",
  "y" : "y2",
  "z.z1" : "z11",
  "z.z3" : [ 1, {
    "zzz" : "skid",
    "zzz1" : null
  }, 2 ]
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants