通过组合相似的名称来加入和组织 JSON 对象结构

Joining and organizing JSON object structure by combining like names

我有一个独特的 JSON 对象列表(指定为 json_object),所有对象都具有类似的结构,看起来像这样

{
  "WREF": {
    "PSME": {
      "sbt": {
        "upr":   68.34,
        "lwr":   3.02 
      }
    } 
  },
  "WREF": {
    "TSHE": {
      "mbt": {
        "upr":   39.425,
        "lwr":   -6.855 
      }
    } 
  },
  "WREF": {
    "PSME": {
      "mbt": {
        "upr":   119.82,
        "lwr":   16.02 
      }
    } 
  },
  "ABBY": {
    "PSME": {
      "sbt": {
        "upr":   84.42,
        "lwr":   9.02 
      }
    } 
  },
  "ABBY": {
    "TSHE": {
      "sbt": {
        "upr":   39.05,
        "lwr":   2.01 
      }
    } 
  },
  "ABBY": {
    "TSHE": {
      "mbt": {
        "upr":   69.35,
        "lwr":   4.07 
      }
    } 
  }
}

我正在尝试 reorganize/restructure 将它们整理成这样更有条理的东西:

{
  "WREF": {
    "PSME": {
      "sbt": {
        "upr":   68.34,
        "lwr":   3.02 
      },
      "mbt": {
        "upr":   119.82,
        "lwr":   16.02 
      }
    },
    "TSHE": {
      "mbt": {
        "upr":   39.425,
        "lwr":   -6.855 
      }
    }  
  },
  "ABBY": {
    "PSME": {
      "sbt": {
        "upr":   84.42,
        "lwr":   9.02 
      }
    },
    "TSHE": {
      "sbt": {
        "upr":   39.05,
        "lwr":   2.01 
      },
      "mbt": {
        "upr":   69.35,
        "lwr":   4.07 
      }
    }  
  },
}

我目前正在使用这段代码来完成它,但是它似乎只是将 JSON 的最高级别放在一起,例如 WREF 和 ABBY,而不是合并 PSME 和 TSHE 或任何较低级别的内容在 JSON 结构中。

#loop through each object
lapply( X = seq( 2, length( json_object), 1), FUN = function( x){
      #if its the second object
      if( x == 2){
        #check if the first objects name matches and join
        if( names( json_object[[ 1]]) %in% names( json_object[[ x]])){
          final_object <<- Map( c, json_object[[1]], json_object[[ x]])
        } else{
          final_object <<-  c( json_object[[ 1]], json_object[[ x]])
        }
      } else{   #if not the second object
        #check if there are any matching names 
        if( names( json_object[[ x]]) %in% names( final_object)){
          #join matching names
          final_object[ names( json_object[[ x]])] <<- Map( c, final_object[ names( json_object[[ x]])],
                                                          json_object[[ x]]
                                                          )
        } else{ #if not, just join
          final_object <<- c( final_object, json_object[[ x]])
        }
        
      }
    })

本例中的最终对象是这样的:

{
  "WREF": {
    "PSME": {
      "sbt": {
        "upr":   68.34,
        "lwr":   3.02 
      },
    },
    "PSME": {
      "mbt": {
        "upr":   119.82,
        "lwr":   16.02 
      }
    },
    "TSHE": {
      "mbt": {
        "upr":   39.425,
        "lwr":   -6.855 
      }
    }  
  },
  "ABBY": {
    "PSME": {
      "sbt": {
        "upr":   84.42,
        "lwr":   9.02 
      }
    },
    "TSHE": {
      "sbt": {
        "upr":   39.05,
        "lwr":   2.01 
      }
    },
    "TSHE": {
      "mbt": {
        "upr":   69.35,
        "lwr":   4.07 
      }
    }  
  }
}

有没有简单的方法来做到这一点?最终我想用更复杂的 JSON 结构来做到这一点。

试试这个,将 txt1 定义为您的第一个 text/code 块:

json1 <- jsonlite::parse_json(txt1)
out1 <- lapply(
  split(json1, names(json1)),
  function(z) {
    y <- do.call(c, unname(z))
    lapply(split(y, names(y)),
           function(x) do.call(c, unname(x)))
  })

jsonlite::toJSON(out1, pretty = TRUE, auto_unbox = TRUE)

产生

{
  "ABBY": {
    "PSME": {
      "sbt": {
        "upr": 84.42,
        "lwr": 9.02
      }
    },
    "TSHE": {
      "sbt": {
        "upr": 39.05,
        "lwr": 2.01
      },
      "mbt": {
        "upr": 69.35,
        "lwr": 4.07
      }
    }
  },
  "WREF": {
    "PSME": {
      "sbt": {
        "upr": 68.34,
        "lwr": 3.02
      },
      "mbt": {
        "upr": 119.82,
        "lwr": 16.02
      }
    },
    "TSHE": {
      "mbt": {
        "upr": 39.425,
        "lwr": -6.855
      }
    }
  }
}

目前这是硬编码的两层深度。如果你需要它是任意的,那么上面的递归改编适用于这个例子;请注意,我还没有测试过其他类型的列表结构。

func <- function(obj) {
  if (!is.list(obj)) return(obj)
  tmp1 <- lapply(split(obj, names(obj)),
                 function(z) do.call(c, unname(z)))
  lapply(tmp1, func)
}

out2 <- func(json1)
jsonlite::toJSON(out2, pretty = TRUE, auto_unbox = TRUE)

呈现与上述类似的输出,但由于递归性质,它不能确保保留列表的顺序。