簡體   English   中英

JSON 到自定義 object 層次結構

[英]JSON to a custom object hierarchy

我有一些 JSON,它由一組具有 ID 和名稱的對象組成,還有另一個 object 給出了父對象的 ID 和名稱。 它本質上是一個文件夾結構,所以根文件夾會有子文件夾,它們也會有子文件夾等。

{
  "data": [
    {
      "id": 66880231, //unique
      "name": "root", //not unique
      "parent": null
    },
    {
      "id": 68102146,
      "name": "Dummy",
      "parent": {
        "id": 66880231,
        "name": "root"
      }
    },
    {
      "id": 68509957,
      "name": "Test - Dummy",
      "parent": {
        "id": 68102146,
        "name": "Dummy"
      }
    },
    {
       "id": 68509998,
      "name": "Another Folder",
      "parent": {
        "id": 68102146,
        "name": "Dummy"
      }
    }
    
  ]
}

我將其反序列化為一個名為 ClioFolders 的ClioFolders

接下來,我需要遍歷每個ClioFolders對象並將它們放入一個名為AllClioFolders的新 object 中,但它不會列出父級,而是成為父級的子 object。 我假設List是這樣做的方法,但我不確定。

這是自定義 object 的 class:

public class AllClioFolders
{
    public string Id { get; set; }
    public string Name { get; set; }  
    public List<AllClioFolders> Children { get; set; }

}

實際上,我將擁有 18,000 多個對象,而且它們不一定是有序的。 每個都需要作為子 object 添加到其父級。

我能想到的最好的解釋方式是展示它在 JSON 中的樣子:

{
  "id": 66880231,
  "name": "root",
  "children": [
    {
      "id": 68102146,
      "name": "Dummy",
      "children": [
        {
          "id": 68509957,
          "name": "Test - Dummy",
          "children": []
        },
        {
          "id": 68509998,
          "name": "Another Folder",
          "children": []
        }
      ]
    }
  ]
}

我面臨的問題是我無法弄清楚如何將 object 添加到相關的父 object 中。 我幾乎可以肯定需要使用 LINQ,但這超出了我的 c# 知識。 任何幫助將不勝感激。

foreach(var folder in GetFolders.Data)
{
    if(folder.Parent == null)
    {
        //Root object
        AllClioFolders.Add(new AllClioFolders { Name = folder.Name, Id = folder.Id.ToString() });
    }
    else
    {
        //Child Object
        //Add this object to the correct parent object
        // AllClioFolders.Add(????);
    }
            
}

更新:我懷疑這樣的事情應該可以工作,但它只會添加到頂級對象的子 object,它需要能夠查看所有子對象。

var obj = AllClioFolders.FirstOrDefault(x => x.Id == folder.Parent.ToString());
if (obj != null) obj.Children.Add(new AllClioFolders { Name = folder.Name, Id = folder.Id.ToString() });

我認為答案取決於。 取決於你想獲得什么。

您在示例 json 中顯示的內容只不過是一個樹結構。

您有第一個 json 但相反(您有指向父級的指針,而不是將它們指向子級),因為父級只有一個。

因此,如果您想在 object 中重現樹結構,您已經足夠接近,您只需要使用遞歸即可。

AllClioFolders rootClioFolder;
List<AllClioFolders> orphans;
foreach(var folder in GetFolders.Data)
{
  AllClioFolders currentFolder=new AllClioFolders { Name = folder.Name, Id = folder.Id.ToString() };
    if(folder.Parent == null)
    {
        //Root object
        rootClioFolder=currentFolder;
    }
    else
    {
         AllClioFolders parentFolder=findParent(currentFolder.Id,rootClioFolder);
        if (parentFolder!=null){
            parentFolder.Children.Add(currentFolder);
        }else{
            orphans.Add(currentFolder)
        }
    }
            
}


function AllClioFolders findParent(string Id,AllClioFolders treeFolder){
    AllClioFolders resultFolder=null;
    if (currentFolder.Id==Id){
        resultFolder=treeFolder;
    }else{
        foreach (AllClioFolders children in treeFolder.Children){
              resultFolder=findParent(Id,children);
              if (resultFolder!=null) break;
        }
    }
    return resultFolder;
}

筆記:

  • 代碼未經測試,僅說明邏輯,如有損壞請修復。
  • json 中的項目可以不按順序排列,但您必須始終在父母之后有孩子。
  • 您不能使用 linq 來訂購由於您的示例,您的父母的數字 ID 高於和低於兒童。
  • 如果您的順序錯誤(父母在孩子之后),您可以通過多次 foreach 來解決它,直到所有孤兒都找到他們的父母。

但是,我建議更改 class 並僅使用Dictionary<string,AllClioFolders> ,其中 Id 是鍵,因此您可以簡單地通過 id 直接訪問並且可以迭代。

編輯:我注意到我讀錯了,ID 是增量的,如果是這種情況,那么你只需要做GetFolders.Data.OrderBy(function (folder) folder.Id)

我已經嘗試過這種方法並且效果很好。
父 id對所有進行分組,並遞歸填充每個parent的所有children

1 - 類:
請注意,我已將AllClioFolders中的Id類型更改為Int

public  class RootObject
{
    public List<ClioFolder> Data { get; set; }
}

public class Parent
{
    public int Id { get; set; }

    public string Name { get; set; }
}

public class ClioFolder
{
    public int Id { get; set; }

    public string Name { get; set; }

    public Parent Parent { get; set; }
}

public class AllClioFolders
{
    public int Id { get; set; }

    public string Name { get; set; }

    public List<AllClioFolders> Children { get; set; }

}

2 - Json

string json = @"{
                  'data': [
                    {
                      'id': 66880231,
                      'name': 'root',
                      'parent': null
                    },
                    {
                      'id': 68102146,
                      'name': 'Dummy',
                      'parent': {
                        'id': 66880231,
                        'name': 'root'
                      }
                    },
                    {
                      'id': 68509957,
                      'name': 'Test - Dummy',
                      'parent': {
                        'id': 68102146,
                        'name': 'Dummy'
                      }
                    },
                    {
                       'id': 68509998,
                      'name': 'Another Folder',
                      'parent': {
                        'id': 68102146,
                        'name': 'Dummy'
                      }
                    }

                  ]
                }";

3 - json 反序列化,構造父級並按父級 ID 對子級進行分組:

List<ClioFolder> allClios = JsonConvert.DeserializeObject<RootObject>(json)?.Data;

//get parent
ClioFolder clioFolder = allClios.FirstOrDefault(c => c.Parent == null);
AllClioFolders allClioParent = new AllClioFolders
{
    Id = clioFolder.Id,
    Name = clioFolder.Name,
    Children = new List<AllClioFolders>()
};

// group by parent id
Dictionary<int, List<ClioFolder>> groupedChilds = allClios
    .Where(c => c.Parent != null)
    .GroupBy(c => c.Parent.Id)
    .ToDictionary(k => k.Key, v => v.ToList());
    
AddChildrenRecursively(groupedChilds, allClioParent);

string result = JsonConvert.SerializeObject(allClioParent);

Console.WriteLine(result);

4 - 方法的實施

static void AddChildrenRecursively(Dictionary<int, List<ClioFolder>> groupeChilds, AllClioFolders allClioParent)
{
    if (groupeChilds.ContainsKey(allClioParent.Id))
    {
        allClioParent.Children = groupeChilds[allClioParent.Id].Select(x => new AllClioFolders { Id = x.Id, Name = x.Name }).ToList();

        foreach (AllClioFolders childOfChild in allClioParent.Children)
        {
            AddChildrenRecursively(groupeChilds, childOfChild);
        }
    }
}

結果

{
   "Id":66880231,
   "Name":"root",
   "Children":[
      {
         "Id":68102146,
         "Name":"Dummy",
         "Children":[
            {
               "Id":68509957,
               "Name":"Test - Dummy",
               "Children":null
            },
            {
               "Id":68509998,
               "Name":"Another Folder",
               "Children":null
            }
         ]
      }
   ]
}

我希望你覺得這有幫助。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM