【问题标题】:Joining and organizing JSON object structure by combining like names通过组合相似的名称来加入和组织 JSON 对象结构
【发布时间】:2021-12-03 06:07:12
【问题描述】:

我有一个独特的 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 
      }
    } 
  }
}

我正在尝试将它们重新组织/重组成更有条理的东西:

{
  "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 结构来做这件事。

【问题讨论】:

    标签: r json list lapply


    【解决方案1】:

    试试这个,将txt1定义为你的第一个文本/代码块:

    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)
    

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

    【讨论】:

    • 您可能希望将auto_unbox = TRUE 参数添加到toJSON 函数。
    • Walleo,这对你有用吗?
    • 谢谢@deschen,是的,这是最后的润色。
    • 对不起@deschen,我最初把你的 OP 弄糊涂了。不,我不知道如何以“整洁”的方式做到这一点,而不是用 purrr::map 或类似的方式替换 lapply,这肯定是一种非常肤浅的 tidyversification。
    • @r2evans 是的!这个递归函数效果很好!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-02-05
    • 1970-01-01
    相关资源
    最近更新 更多