1

I have the following JSON:

 {
    "graph": {
        "edges": [{
            "fromNode": "1",
            "toNode": "2",
            "distance": 200
        }],
        "nodes": [{
            "id": "1",
            "lat": 10.402875,
            "lng": 53.611151
        }]
    }
}

For the deserialization I have this classes:

public class Graph {

    public Node [] nodes { get; set; }
    public Edge [] edges { get; set; }
}

public class Node {

    public string id { get; set; }
    public double lat { get; set; }
    public double lng { get; set; }
}

public class Edge {

    public string fromNode { get; set; }
    public string toNode { get; set; }
    public int distance { get; set; }
}

When I want to deserialize the JSON I call this function:

JsonConvert.DeserializeObject<Graph> (content);

Now I want to get the referenced node object in the edge class by the deserialization like this:

public class Edge {

    public Node fromNode { get; set; }
    public Node toNode { get; set; }
    public int distance { get; set; }
}

Do you have an example for this without an foreach loop after the deserialization?

Maxim
  • 317
  • 1
  • 5
  • 13
  • Can you modify the JSon and parse nodes first ? – Mat Jun 21 '17 at 14:15
  • 1
    This is not possible by simply deserialization. Once you get the graph object using deserialization you need to write logics to get fromNode and toNode objects by id – Chetan Jun 21 '17 at 14:18
  • Is there an example of optional logic to get an object by id? – Maxim Jun 21 '17 at 14:22
  • Search the nodes collection by node id and you have the node for the id - it is as simple as it sounds – Sir Rufo Jun 21 '17 at 14:29

2 Answers2

1

One way to do it would be to write your own JsonConverter (as shown Here) and keep track of your node ID's (in a Dictionnary for example) during the deserialization process. Then you can simply retrieve the corresponding Edges everytime when you create a new Node.

So in your custom converter you'd have something like this:

public override object ReadJson(JsonReader reader, Type objectType
        , object existingValue, JsonSerializer serializer)
{

    Graph graph = new Graph();
    List<Edge> graphEdges = new List<Edge>();
    List<Node> graphNodes = new List<Node>();

    Dictionnary<int, List<Edge>> fromNodesMap = new Dictionnary<int, List<Edge>>();
    Dictionnary<int, List<Edge>> toNodesMap = new Dictionnary<int, List<Edge>>();

    /* Parse the 'edges' array, I'm omitting the reading stuff here */

    var edge = new Edge();

    int fromNode = Convert.ToInt32(((JValue)obj["fromNode"]).Value);
    if (fromNodesMap.Contains(fromNode)) {
        fromNodesMap[fromNode].Add(edge);
    } else {
        var edgeList = new List<Edge>();
        edgeList.Add(edge);
        fromNodesMap.Add(fromNode, edgeList);
    }

    int toNode = Convert.ToInt32(((JValue)obj["toNode"]).Value);
    if (toNodesMap.Contains(toNode)) {
        toNodesMap[toNode].Add(edge);
    } else {
        var edgeList = new List<Edge>();
        edgeList.Add(edge);
        toNodesMap.Add(toNode, edgeList);
    }

    edge.distance = Convert.ToInt32(((JValue)obj["distance"]).Value);

    graphEdges.Add(edge);

    /* Parse the 'nodes' array, I'm omitting the reading stuff here */

    var node = new Node();
    int nodeId = Convert.ToInt32(((JValue)obj["id"]).Value);
    node.lat = Convert.ToDouble(((JValue)obj["lat"]).Value);
    node.lng = Convert.ToDouble(((JValue)obj["lng"]).Value);

    var listEdgesSameFrom = fromNodesMap[nodeId];
    foreach (var edge in listEdgesSameFrom)
        edge.fromNode = node;

    var listEdgesSameTo = toNodesMap[nodeId];
    foreach (var edge in listEdgesSameTo)
        edge.toNode = node;

    graphNodes.Add(node);

    /* Read till end */

    graph.edges = graphEdges.ToArray();
    graph.nodes = graphNodes.ToArray();

    return graph;
}

Disclaimer I haven't tested it, but the logic is there.

Now I know there are foreach loops in there but the difference is that the only searching there is is to get the lists from the dictionnaries, and that's pretty minimal I think. I hope this helps or at least give you another way to look at it.

Mat
  • 1,440
  • 1
  • 18
  • 38
0

I would suggest you write extension methods for Edge to return the nodes:

public static class ExtensionMethods
   {
       public static Node FromNode(this Edge edge, Graph graph){
            return graph.Nodes.FirstOrDefault(n => n.id.Equals(edge.fromNode);
       }

       public static Node ToNode(this Edge edge, Graph graph){
            return graph.Nodes.FirstOrDefault(n => n.id.Equals(edge.toNode);
       }
   }

After that you can call edge.FromNode(graph) and get the from node back. The advantage is that you do not need to put the methods to retrieve the Nodes in your Node class and do not need to hold a parent relation to the graph from each edge.

PtrBld
  • 64
  • 1
  • 6