【问题标题】:Creating a tree using json from a list/table使用列表/表中的 json 创建树
【发布时间】:2012-05-18 21:50:55
【问题描述】:

假设在这种情况下我有这样的表/列表 n=3,但 n 可以是无限的。

groupid       answerid1     answerid2     answerid(n)
1              3            6             8 
1              3            6             9 
1              4            7               
2              5                            

我想使用 java 创建一个像这样的父/子树 json 输出。(我一直在使用 GSON)

    {
        data: [
            {
                groupid: 1,
                children: [
                    {
                        answerid1: 1,
                        children: [
                            {
                                answerid2:3,
                                children: [
                                           {
                                    answerid3:6,
                                                  children: [
                                                              {answerid4: 8},
                                  {answerid4: 9} 
                                                             ]
                                              } 


                            }, {
                                 answerid2: 4,
                                 children: [
                                          {answerid3:7} 
                                   ]
                                 }
                                ]         
                    }, 

               {
                 groupid1: 2,
                 children: [
                       { answerid2: 5}
                        ]
                }

               ]      
        }

这样做的代码/步骤是什么。我查看了很多标签,但大多数人都在打印输出,而不是递归地为 GSON 构建一个 hashmap/ArrayList 来解析并写入 API。另外一点,每个 id 都有与之关联的其他数据,这些数据必须包含在 json 输出中。例如,而不是 {groupid:1} 需要这个 {groupid:1, text=toyota}。

非常感谢任何帮助,因为我来自 SAS 背景,对 java 还很陌生。

我得到这样的数据(只是一个列表矩阵) 丰田、汽油、紧凑型、卡罗拉

  • 丰田、汽油、紧凑型、凯美瑞
  • 丰田、混合动力、紧凑型、普锐斯
  • 本田、汽油、紧凑型、思域
  • 如果需要,我可以将数据重新格式化为两个表

    parentId parText answerId

  • 1 丰田 1
  • 1 丰田 2
  • 1 丰田 3
  • 2 本田 4
  • answerId 级别 answerTextid answerText

  • 1 1 1 气体
  • 1 2 2 紧凑
  • 1 3 3 花冠
  • 2 1 1 气体
  • 2 2 2 紧凑
  • 2 3 4 凯美瑞
  • 然后我需要将其设为树(嵌套输出,如 JSON 显示父/子 - 就像您创建文件系统目录一样)

    我想做的另一件事是每辆车都有里程作为变量 ({answerid3:4, text=Corolla, mileage=38}。但如果我遍历树,请给出分支的平均里程. 就像在丰田、Gas、Compact 分公司说的那样,里程数是 avg(Camry, Corolla)

    输出有点偏,我正在寻找这样的东西。如果没有孩子则没有孩子数组列表,并且属性是一个对象的一部分(哈希图)

    {"data":[{"id":1,"children":
        [{"id": 2,"children":
            [{"id": 3 ,"children":
                [{"id": 4,"name":"Prius"}],"name":"Compact"}],"name":"Hybrid"},
        {"id":5,"children":
            [{"id":3,"children":
                [{"id":7,"MPG":38, "name":"Corolla"},
                 {"id":8,"MPG":28,"name":"Camry"}],"name":"Compact"}],"name":"Gas"}],"name":"Toyota"},
    {"id":9, "children":
        [{"id":10,"children":
            [{"id":3 ,"children":
                [{"id":11 ,"name":"Civic"}],"name":"Compact"}],"name":"Gas"}],"name":"Honda"}]}
    
  • 【问题讨论】:

      标签: java json tree


      【解决方案1】:

      您应该按照您需要的结构创建类来为您的数据建模。您基本上想从一些基于行的数据构建层次结构,这很像 XML 文档,这可能是一个合适的解决方案。但是你让我上瘾了,所以我玩弄了我以前的东西并想出了这个:

      public class Test { 
      
          public static void main(String[] args) 
          {
              // hierarchical data in a flattened list
              String[][] data = {
                      {"Toyota", "Gas", "Compact", "Corolla"},
                      {"Toyota", "Gas", "Compact", "Camry"},
                      {"Toyota", "Hybrid", "Compact", "Prius"},
                      {"Honda", "Gas", "Compact", "Civic"}
              };
      
              TreeManager treeManager = new TreeManager();
      
              for(String[] row : data)
              {
                  // build the path to our items in the tree
                  List<String> path = new ArrayList<String>();
                  for(String item : row)
                  {
                      // add this item to our path
                      path.add(item);
                      // will add it unless an Item with this name already exists at this path
                      treeManager.addData(treeManager, path);
                  }
              }
      
              treeManager.getData(data[0]).putValue("MPG", 38);
              treeManager.getData(data[1]).putValue("MPG", 28);
      
              Gson gson = new Gson();
      
              System.out.println(gson.toJson(treeManager));
          }
      
          /**
           * This base class provides the hierarchical property of
           * an object that contains a Map of child objects of the same type.
           * It also has a field - Name
           *
           */
          public static abstract class TreeItem implements Iterable<TreeItem>{
      
              private Map<String, TreeItem> children;     
              private String name;
      
              public TreeItem() {
                  children = new HashMap<String, TreeItem>();
              }
      
              public String getName() {
                  return name;
              }
      
              public void setName(String name) {
                  this.name = name;
              }
      
              public void addChild(String key, TreeItem data) 
              {           
                  children.put(key, data);
              }
      
              public TreeItem getChild(String key) 
              {           
                  return children.get(key);
              }
      
              public boolean hasChild(String key) 
              {           
                  return children.containsKey(key);
              }
      
              @Override
              public Iterator<TreeItem> iterator() {          
                  return children.values().iterator();
              }           
          }
      
          /**
           * This is our special case, root node. It is a TreeItem in itself
           * but contains methods for building and retrieving items from our tree
           *
           */
          public static class TreeManager extends TreeItem
          {       
              /**
               * Will add an Item to the tree at the specified path with the value
               * equal to the last item in the path, unless that Item already exists 
               */
              public void addData(List<String> path)
              {
                  addData(this, path);
              }
      
              private void addData(TreeItem parent, List<String> path)
              {
                  // if we're at the end of the path - create a node
                  String data = path.get(0);
                  if(path.size() == 1)
                  {
                      // unless there is already a node with this name
                      if(!parent.hasChild(data))
                      {
                          Group group = new Group();
                          group.setName(data);
                          parent.addChild(data, group);
                      }
                  }
                  else
                  {
                      // pass the tail of this path down to the next level in the hierarchy
                      addData(parent.getChild(data), path.subList(1, path.size()));
                  }
              }
      
              public Group getData(String[] path)
              {
                  return (Group) getData(this, Arrays.asList(path));
              }
      
              public Group getData(List<String> path)
              {
                  return (Group) getData(this, path);
              }
      
              private TreeItem getData(TreeItem parent, List<String> path)
              {
                  if(parent == null || path.size() == 0)
                  {
                      throw new IllegalArgumentException("Invalid path specified in getData, remainder: " 
                              + Arrays.toString(path.toArray()));
                  }
                  String data = path.get(0);
                  if(path.size() == 1)
                  {
                      return parent.getChild(data);
                  }
                  else
                  {
                      // pass the tail of this path down to the next level in the hierarchy
                      return getData(parent.getChild(data), path.subList(1, path.size()));
                  }
              }
          }
      
          public static class Group extends TreeItem {
      
              private Map<String, Object> properties;
      
              public Object getValue(Object key) {
                  return properties.get(key);
              }
      
              public Object putValue(String key, Object value) {
                  return properties.put(key, value);
              }
      
              public Group () {
                  super();
                  properties = new HashMap<String, Object>();
              }       
          }
      }
      

      我认为这满足了您迄今为止提到的大部分要求,尽管我没有将 MPG 值的平均值作为读者的练习(我只有这么多时间......)。此解决方案非常通用 - 您可能需要更具体的子类来更好地描述您的数据模型(如制造商、类型、模型),因为您将能够从它们身上挂起更多有用的方法(如计算子类中字段的平均值对象) ,并且您不必将属性作为Objects 的集合来处理,但是您会得到更复杂的代码来从列表中初始化您的数据结构。注意 - 这不是生产就绪代码,我只是提供了一个示例,说明您可以如何使用 Java 对数据进行建模。

      如果您不仅不熟悉 Java,而且不熟悉 Object Orientated Programming,那么您应该阅读该主题。我在这里写的代码并不完美,我已经看到了可以改进的方法。学习编写高质量的面向对象代码需要时间和实践。阅读Design PatternsCode Smells

      【讨论】:

      • 感谢您的帮助。但是,创建一个提供(具有答案列表的对象)属性的抽象超类并通过扩展它来创建您的 Group 和 Answer 对象是什么意思。对我来说,我认为这是我一直在尝试做的,但不知道是否有用。我一直在尝试使用 hashmaps 和 arraylist 来制作一个“大”对象并让 GSON 解析它。
      • 在上面的代码中,您添加到每个答案数组列表中,但是如何遍历初始“列表”以获得所需的输出?这就是我一直在做的事情,其中​​级别是每行的“级别” HashMap map = new HashMap (); for (int i = 0; i
      • 我已经更新了这个例子来告诉你我所说的抽象超类是什么意思。我认为我在这里缺少的是对您的数据如何进入以及如何构建的理解。您的输入似乎是一个包含答案列表的组列表(单级 - 只是一个列表列表,但在您的输出 JSON 中,您有一个答案中包含嵌套级别答案的组,我不太明白如何您希望从一个到另一个。如果您有更多详细信息,请更新您的原始问题。
      • 感谢大家对面向对象链接的帮助。我的经验主要是VB(VBA)、SAS、SQL编程。如果您需要任何统计/数学、SAS、SQkl 帮助联系我,我将很乐意回报您。
      • 不用担心,您只需点赞并接受我的回答即可表达您的感激之情 :)
      猜你喜欢
      • 1970-01-01
      • 2012-09-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多