简体   繁体   中英

Doubly Linked List to JSON

I've a three dimensional structure ... actually a doubly linked list with six nodes ie left, right, up, down, in, out. if one node is on the right side of other then that node will be defiantly on the left side of the first one. like

3D实际数据结构的2D样本

Actually this is a 3D structure, but for understanding purposes, I've given a 2D example. Now I've to convert it in JSON format, to send this data through WCF to a client, but as it contains loops so it couldn't be converted to JSON. I've these questions

  1. Can this type of doubly linked list be converted to JSON?
  2. Is there another way to do that?
  3. Any Other recommended Data Structure? If this is impossible using Doubly Linked List.

I'm using Json.Net to handle JSON.

My class is

public class Node
{
    public Document document = null;

    public Node left = null;
    public Node right = null;
    public Node up = null;
    public Node down = null;
    public Node inside = null;
    public Node outside = null;
}

Json.Net can handle reference loops if you set the PreserveReferencesHandling option in the settings.

JsonSerializerSettings settings = new JsonSerializerSettings
{
    PreserveReferencesHandling = PreserveReferencesHandling.Objects,
    Formatting = Formatting.Indented
};
string json = JsonConvert.SerializeObject(rootNode, settings);

This setting will cause the JSON to be written with special $id and $ref properties which allow the JSON to be deserialized back to the original references, assuming you are using Json.Net to deserialize on the client side. With this in place you should be able to use your existing object structure with no problem.

Demo:

using System;
using System.Collections.Generic;
using Newtonsoft.Json;

public class Program
{
    public static void Main()
    {
        Node center = new Node { Name = "In House" };
        Node north = new Node { Name = "North of House" };
        Node west = new Node { Name = "Front of House" };
        Node east = new Node { Name = "Back of House" };
        Node south = new Node { Name = "South of House" };

        center.East = east;
        east.West = center;

        center.West = west;
        west.East = center;

        east.North = north;
        north.East = east;

        east.South = south;
        south.East = east;

        south.West = west;
        west.South = south;

        west.North = north;
        north.West = west;

        DumpNodes(center);

        Console.WriteLine();

        JsonSerializerSettings settings = new JsonSerializerSettings();
        settings.PreserveReferencesHandling = PreserveReferencesHandling.Objects;
        settings.NullValueHandling = NullValueHandling.Ignore;
        settings.Formatting = Formatting.Indented;

        string json = JsonConvert.SerializeObject(center, settings);
        Console.WriteLine(json);

        Node node = JsonConvert.DeserializeObject<Node>(json, settings);

        Console.WriteLine();

        DumpNodes(node);
    }

    private static void DumpNodes(Node startingNode)
    {
        HashSet<Node> seen = new HashSet<Node>();
        List<Node> queue = new List<Node>();
        queue.Add(startingNode);
        while (queue.Count > 0)
        {
            Node node = queue[0];
            queue.RemoveAt(0);
            if (!seen.Contains(node))
            {
                seen.Add(node);
                Console.WriteLine(node.Name);
                Look("north", node.North, queue, seen);
                Look("west", node.West, queue, seen);
                Look("east", node.East, queue, seen);
                Look("south", node.South, queue, seen);
            }
        }
    }

    private static void Look(string dir, Node node, List<Node> queue, HashSet<Node> seen)
    {
        if (node != null)
        {
            Console.WriteLine("   " + dir + ": " + node.Name);
            if (!seen.Contains(node))
            {
                queue.Add(node);
            }
        }
    }
}

public class Node
{
    public string Name { get; set; }
    public Node North { get; set; }
    public Node South { get; set; }
    public Node East { get; set; }
    public Node West { get; set; }
}

Output:

In House
   west: Front of House
   east: Back of House
Front of House
   north: North of House
   east: In House
   south: South of House
Back of House
   north: North of House
   west: In House
   south: South of House
North of House
   west: Front of House
   east: Back of House
South of House
   west: Front of House
   east: Back of House

{
  "$id": "1",
  "Name": "In House",
  "East": {
    "$id": "2",
    "Name": "Back of House",
    "North": {
      "$id": "3",
      "Name": "North of House",
      "East": {
        "$ref": "2"
      },
      "West": {
        "$id": "4",
        "Name": "Front of House",
        "North": {
          "$ref": "3"
        },
        "South": {
          "$id": "5",
          "Name": "South of House",
          "East": {
            "$ref": "2"
          },
          "West": {
            "$ref": "4"
          }
        },
        "East": {
          "$ref": "1"
        }
      }
    },
    "South": {
      "$ref": "5"
    },
    "West": {
      "$ref": "1"
    }
  },
  "West": {
    "$ref": "4"
  }
}

In House
   west: Front of House
   east: Back of House
Front of House
   north: North of House
   east: In House
   south: South of House
Back of House
   north: North of House
   west: In House
   south: South of House
North of House
   west: Front of House
   east: Back of House
South of House
   west: Front of House
   east: Back of House

Working fiddle here: https://dotnetfiddle.net/EojsFA

What you have is a network. One representation of this is a list of edges. Yours are all bidirectional it seems so it could look like this:

[
    {source:"Left Node", destination:"Center Node"},
    {source:"Center Node", destination:"Up Node"},
    {source:"Center Node", destination:"Down Node"},
    {source:"Center Node", destination:"Right Node"},
    ...
]

You could spit out Json using a traversal of the network. The specific algorithms depend on the specific network you have. However searching on network should give you all the sample code you need.

Doubly linked list is certainly NOT what you need unless you have an extremely specific network that can be traversed in sequence using each edge once only.

Another possibility is that you are really just dealing with Voxels. That is, all your nodes are just coordinates in a 3d cube. The fact that one voxel is adjacent to another then means there is a connection. So if Left Node is at <1,1,1> and Center Node is at <1,2,1> there is a connection because all the coordinates are the same except for Y which differs by only 1. Storage is simply a list of the existing nodes.

Your question mentions a 3D structure, so there seems to be a Voxel representation if nodes are all at a particular distance. If instead the distances are random then you would need to go the network route.

Any 3D array (or array of any dimensions for that matter), is essentially a 1D array. You can even think of all arrays being 1D, because a 2D array can be interpreted (logically) as an array of arrays, 3D is an array of arrays of arrays, and so on.

If your structure is like a cubic shape, then it is just a 3D array. It doesn't matter that it is stored in a link list. So to do that, just grab one corner (say low left out), then go through your structure line by line, plane by plane and store objects into a 1D (or 3D) array. Construct it in the same way at the other end.

Your serialization would look something like this (where (x,y,z) is whatever content you have for each node)

[(0,0,0), (0,0,1), (0,0,2), (0,0,3), (0,1,0), (0,1,1), (0,1,2), (0,1,3), ...]

If your structure has an arbitrary 3D shape, then arbitrary pick any node, then view the rest as a tree structure. Each element can have a maximum of 6 child nodes. So let say you pick the "center node", you'd first describe what child nodes it has, then later describe the child nodes of the child nodes, if they have any. Give each node an unique ID to distinguish them. It is important that you describe a node as a child node before you describe the child node of that node, otherwise you'd not be able to construct it at the other end.

Your structure would look like this:

[{id=0, left=1,right=2,up=3,down=null,in=4,out=5},
{id=1, left=6, right=0, up=7, down=null, in=8, out=9},
...]

You can safely ignore any 2-way info in the link list if you wish, because the second way is redundant.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM