0

For some reason I cannot append a string variable to string[] value in Dictionary<string;string[]>

I am trying to make a Graph C# class for practice and i ran into a problem: I use Dictionary<string, string[]> graph to make a structure like this:

"Node1":[connection1,connection2,connection3]
"Node2":[connection1,connection2,connection3]
"Node3":[connection1,connection2,connection3]
...

I have a method to append a connections array value:

// from Graph class
private Dictionary<string, string[]> graph;

public void AddEdge(string NodeName, string EdgeName)
{
    graph[NodeName].Append(EdgeName);
}

And use it like this:

//from Main
Graph g = new Graph();
string[] Nodes = { "node1", "node2", "node3" };
string[][] Edges = { new[] { "node1", "nodeToEdgeTo" }, new[] { "node2", "nodeToEdgeTo" } }; 
//nodeToEdgeTo are nodes like "node2" or "node3"

foreach (var i in Edges)
{
    g.AddEdge(i[0], i[1]);
}

But as a result i get empty values for some reason:

"Node1":[]
"Node2":[]
"Node3":[]

I have no idea why

LaPepega
  • 11
  • 2
  • 3
    Arrays are not resizable, use `List` instead. – Dai Feb 08 '23 at 16:28
  • @Dai What do you mean? Arrays literally have .Append() method. Or are they only not resizable in Dictionaries? – LaPepega Feb 08 '23 at 16:33
  • 1
    `.Append()` does not do what you think it does: it's not a member method of `T[]`, it's a Linq extension method that returns a new lazily-evaluated iterable/enumerable. It doesn't mutate the target array at all. – Dai Feb 08 '23 at 16:33
  • Append (you presumably found the Linq one for Enumerables) creates a new Array not changes the existing Array. Array can't be changed in size. – Ralf Feb 08 '23 at 16:35
  • 1
    Also, in the C#/.NET world method parameters are `camelCase`, not `PascalCase`. – Dai Feb 08 '23 at 16:35
  • @LaPepega https://stackoverflow.com/questions/16322/learning-about-linq – Dai Feb 08 '23 at 16:38
  • Ooooooh, ok thanks so much, I wanted to use `List` at first but then thought that `string[]` would've been simplier. – LaPepega Feb 08 '23 at 16:40
  • 1- You must `new the dictionary`, otherwise it will give a null reference error //private Dictionary graph; private Dictionary graph = new Dictionary(); 2- If the `key does not exist in the dictionary`, you must `add it first` : public void AddEdge(string NodeName, string EdgeName) { //graph[NodeName].Append(EdgeName); if (!graph.ContainsKey(NodeName)) graph.Add(NodeName, new string[0]); graph[NodeName].Append(EdgeName); } – Hossein Sabziani Feb 08 '23 at 16:43
  • @Dai btw why did you comment and not answer (I'm new to stack owerflow) – LaPepega Feb 08 '23 at 16:44
  • @LaPepega Because I don't care about scoring more reputation points at this point – Dai Feb 08 '23 at 16:52

2 Answers2

0

As people already said, an array (as in most languages) are not resizeables. I think it's interesting to see how you instanciate an array in C to understand that. In C either you instanciate like that

int[5] myArray

or you choose the dynamic way with malloc pretty much like so

int *myArray = malloc(5 *sizeof(int));

What you can see is that when you instanciate them you have to give it a size and it will "lock" a chunck of memory for it.
Now if you want to add more things to it you have to recreate a new one bigger and copy the content from one to another.

Lists work in a different way. each element of a list are alocated separatly and each of them contain a pointer to the next element. That's why it's way easier to add an element to a list. What happens under the hood is that it creates that element and alocate memory for it and make the last (or first it depends) element of the list to it (you can see it as a chain)

It should remind you of what you're trying to achieve with your tree. Graphs and lists aren't much different but graph doesn't already exist int c# so you have to recreate it.

Simple answer

So the easy solution for you case is to swap the array by a list like so:

Dictionary<string, List<string>> graph

and then you use it like so

public void AddEdge(string NodeName, string EdgeName)
{
    graph[NodeName].Add(EdgeName);
}

More complicated answer

So following what we said about list, we should assume that each element of your graph should reference other elements. That will look like so:

using System.Text.Json;

var edge0 = new Edge() { WhatEverData = "level0 : edge0" }; //Your base node/edge


var edge1 = new Edge() { WhatEverData = "level1 : edge1" };
var edge2 = new Edge() { WhatEverData = "level1 : edge2" };
var edge3 = new Edge() { WhatEverData = "level1 : edge3", Edges = new List<Edge> { new Edge() { WhatEverData = "level2" } } };

edge0.AddEdge(edge1);
edge0.AddEdge(edge2);
edge0.AddEdge(edge3);

Console.WriteLine(JsonSerializer.Serialize(edge0));
public sealed class Edge
{
    public string? WhatEverData { get; set; }
    public List<Edge>? Edges { get; set; }

    public Edge AddEdge(Edge toAdd)
    {
        Edges ??= new List<Edge>();
        Edges.Add(toAdd);
        return this;
    }
}

In this example everything is an edge, Edge0 being the root of your graph but your root could also be a list of edge if you really want to.
The point is that now that it's an object you can put pretty much everything you want in there. You can also easily serialize it! Here it's what the output of this tiny code looks like:

{
  "WhatEverData": "level0 : edge0",
  "Edges": [
    { "WhatEverData": "level1 : edge1", "Edges": null },
    { "WhatEverData": "level1 : edge2", "Edges": null },
    {
      "WhatEverData": "level1 : edge3",
      "Edges": [{ "WhatEverData": "level2", "Edges": null }]
    }
  ]
}

Hope it helped

Platypus
  • 321
  • 1
  • 4
  • 17
-1

Instead of an array, you might want a List isntead: Dictionary<string, List<string>>.

Then you could do this:

public void AddEdge(string NodeName, string EdgeName)
{
    graph[NodeName].Add(EdgeName);
}
Joel Coehoorn
  • 399,467
  • 113
  • 570
  • 794