This question already has answers here:
C# dictionary - one key, many values
(15 answers)
Closed 12 days ago.
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
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
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);
}
Related
I have below class
public class HydronicEquipment
{
public List<LibraryHydronicEquipment> Source { get; set; }
public List<LibraryHydronicEquipment> Distribution { get; set; }
public List<LibraryHydronicEquipment> Terminals { get; set; }
}
and then i have the below class for "libraryHydronicEquipment"
public class LibraryHydronicEquipment : IEquipmentRedundancy
{
public string Name { get; set; }
public RedundancyStatus RedundancyStatus { get; set; }
public EquipmentRedundancy EquipmentRedundancy { get; set; }
}
I am trying to concatenate the list of "LibraryHydronicEquipment" objects available from all three properties (i.e) from source, distribution and terminal and General concatenate method will looks like as this below
var source = hydronicEquipment.Source;
var distribution = hydronicEquipment.Distribution;
var teriminals = hydronicEquipment.Terminals;
Source.Concat(Distribution).Concat(Terminals)
I am trying to achieve the same using reflection and the code looks like as below
foreach (var (systemName, hydronicEquipment) in hydronicSystemEquipment)
{
bool isFirstSystem = true;
var equipmentList = new List<string> { "Source", "Distribution", "Terminals" };
var redundancyequipmentList = GetRedundancyEquipment(hydronicEquipment, equipmentList);
}
and the method GetRedundancyEquipment is looks like below
private static IEnumerable<IEquipmentRedundancy> GetRedundancyEquipment(HydronicEquipment hydronicEquipment, List<string> equipmentList)
{
IEnumerable<IEquipmentRedundancy> equipmentRedundancies = new List<IEquipmentRedundancy>();
dynamic equipmentResults = null;
foreach(var equipment in equipmentList)
{
var componentList = hydronicEquipment.GetType().GetProperty(equipment).GetValue(hydronicEquipment, null) as IEnumerable<IEquipmentRedundancy>;
equipmentResults = equipmentRedundancies.Concat(componentList);
}
return equipmentResults;
}
The problem here is even though i have Source is having list of objects and Distribution is having list of objects, the equipmentResults is giving only one object instead of list of concatenated objects.
I am trying to return the IEnumerable<IEquipmentRedundancy> at the end using reflection method but it seems not working with the above code.
Could any one please let me know how can i achieve this, Many thanks in advance.
GetRedundancyEquipment should preserve your values instead of reassign the reference with each iteration. Here's the fixed version:
private static IEnumerable<IEquipmentRedundancy> GetRedundancyEquipment(HydronicEquipment hydronicEquipment, List<string> equipmentList)
{
IEnumerable<IEquipmentRedundancy> equipmentRedundancies = new List<IEquipmentRedundancy>();
var equipmentResults = new List<IEquipmentRedundancy>();
foreach (var equipment in equipmentList)
{
var componentList = hydronicEquipment.GetType().GetProperty(equipment).GetValue(hydronicEquipment, null) as IEnumerable<IEquipmentRedundancy>;
equipmentResults.AddRange(equipmentRedundancies.Concat(componentList));
}
return equipmentResults;
}
If we look at what you're doing in GetRedundancyEquipment() it becomes clear.
First you create equipmentRedundancies = new List<IEquipmentRedundancy>();
Then you never modify equipmentRedundancies - e.g. via Add(). It remains an empty list until it goes out of scope and is garbage collected.
In a loop you then repeatedly make this assignment equipmentResults = equipmentRedundancies.Concat(componentList);
That is to say: Assign to equipmentResults the concatenation of componentList to equipmentRedundancies.
Note that Concat() is a lazily evaluated linq method. When you actually enumerate it results are produced. It doesn't modify anything, it's more like a description of how to produce a sequence.
So each time through the loop you're assigning a new IEnumerable that describes a concatentaion of an empty list followed by the property that you retrieved with reflection to equipmentResults. Then at the end you return the final one of these concatenations of an empty list and retrieved property.
If you want all of them together, you should concatenate each of them to the result of the previous concatenation, not to an empty list.
I'm trying to make a map like this in C#:
0 1
0 [ ]---[ ]
| |
| |
1 [ ]---[ ]
Simple grid with rooms at (0,0), (1,0), (0,1) and (1,1)
I have tried doing this and have an example here https://dotnetfiddle.net/3qzBhy
But my output is:
[ ]|||| [ ]
I don't get why and not sure if calling .ToString() on a StringBuilder makes it lose its formatting such as new lines.
I also had trouble finding a way to store coordinates
Public SortedList<int, int> Rooms ()
{
var roomList = new SortedList<int, int>();
roomList.Add(0,0);
roomList.Add(1,0);
//roomList.Add(0,1);
//roomList.Add(1,1);
return roomList;
}
roomList.Add(0,1) and roomList.Add(1,1) are duplicates because the keys 0 and 1 are already used. How can I store a list of coordinates?
Instead of spreading my opinions via comments I'll just dump em all here as an answer:
I also had trouble finding a way to store coordinates
SortedLists, Dictionaries, etc. won't work. It would be best to just use a regular List filled with Tuples, Points or a class of your own until you find a better solution.
Since those rooms maybe won't stay empty you could write your own classes, e.g.:
class Tile
{
public int X { get; set; }
public int Y { get; set; }
public virtual void Draw(StringBuilder map)
{
map.Append(" ");
}
}
class Room : Tile
{
public int EnemyType { get; set; }
public int Reward { get; set; }
public override void Draw(StringBuilder map)
{
map.Append("[ ]");
}
}
// etc.
I don't get why and not sure if calling .ToString() on a StringBuilder makes it lose its formatting such as new lines.
It doesn't. You didn't have any newlines in your example because all rooms are at Y = 0
The current attempt won't work if you draw multiple lines at once and string them together. Instead you could use something like a "half-step" grid.
You can find a small (ugly, non-optimzed, makeshift) example here as a fiddle.
Besides the problems with text-formatting and the console, and also the options Manfred already mentioned, here is an example which uses an array instead of a list. A room is a true-value at any given index, "no room" is represented by false.
Your Rooms()method looks like this then:
public bool[,] Rooms ()
{
var roomList = new bool[,]{{true,false},{true,true}};
return roomList;
}
Which makes you need to change IsRoom(int, int)to look like this:
public bool IsRoom(int x, int y)
{
var rooms = Rooms();
if(x<rooms.GetLength(0) && y<rooms.GetLength(1))
{
return (rooms[x,y]);
}
return false;
}
Also there was a line-break missing, which lead to having a vertcal connector on the same line as the next room. I changed it to be
if (IsRoom(x, y + 1))
{
buildMap.Append("\r\n".PadLeft(4) + DrawVerticalConnector().PadRight(4));
buildMap.Append("\r\n".PadLeft(4) + DrawVerticalConnector().PadRight(4)+ "\r\n".PadLeft(4));
}
I have just started using Newtonsoft.Json (Json.net). In my first simple test, I ran into a problem when deserializing generic lists. In my code sample below I serialize an object, containing three types of simple integer lists (property, member var and array).
The resulting json looks fine (the lists are converted into json-arrays). However, when I deserialize the json back to a new object of the same type, all list items are duplicated, expect for the array. I've illustrated that by serializing it a second time.
From searching around, I've read that there may be a "private" backing field to the lists that the deserializer also fills.
So my question is: Is there a (preferably simple) way to avoid duplicate items in following case?
Code
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
namespace JsonSerializeExample
{
public class Program
{
static void Main()
{
var data = new SomeData();
var json = JsonConvert.SerializeObject(data);
Console.WriteLine("First : {0}", json);
var data2 = JsonConvert.DeserializeObject<SomeData>(json);
var json2 = JsonConvert.SerializeObject(data2);
Console.WriteLine("Second: {0}", json2);
}
}
public class SomeData
{
public string SimpleField;
public int[] IntArray;
public IList<int> IntListProperty { get; set; }
public IList<int> IntListMember;
public SomeData()
{
SimpleField = "Some data";
IntArray = new[] { 7, 8, 9 };
IntListProperty = new List<int> { 1, 2, 3 };
IntListMember = new List<int> { 4, 5, 6 };
}
}
}
Resulting output
First : {"SimpleField":"Some data","IntArray":[7,8,9],"IntListMember":[4,5,6],"IntListProperty":[1,2,3]}
Second: {"SimpleField":"Some data","IntArray":[7,8,9],"IntListMember":[4,5,6,4,5,6],"IntListProperty":[1,2,3,1,2,3]}
There may be some overlap here with Json.Net duplicates private list items. However, I think my problem is even simpler, and I still haven't figured it out.
That is because you are adding items in the constructor. A common approach in deserializers when processing a list is basically:
read the list via the getter
if the list is null: create a new list and assign via the property setter, if one
deserialize each item in turn, and append (Add) to the list
this is because most list members don't have setters, i.e.
public List<Foo> Items {get {...}} // <=== no set
Contrast to arrays, which must have a setter to be useful; hence the approach is usually:
deserialize each item in turn, and append (Add) to a temporary list
convert the list to an array (ToArray), and assign via the setter
Some serializers give you options to control this behavior (others don't); and some serializers give you the ability to bypass the constructor completely (others don't).
I'm pretty sure that this post is not relevant anymore, but for future reference, here a working solution.
Just need to specify that ObjectCreationHandling is set to Replace, i.e. Always create new objects and not to Auto (which is the default) i.e. Reuse existing objects, create new objects when needed.
var data = new SomeData();
var json = JsonConvert.SerializeObject(data);
Console.WriteLine("First : {0}", json);
var data2 = JsonConvert.DeserializeObject<SomeData>(json, new JsonSerializerSettings() { ObjectCreationHandling = ObjectCreationHandling.Replace });
var json2 = JsonConvert.SerializeObject(data2);
Console.WriteLine("Second: {0}", json2);
I encountered a similar issue with a different root cause. I was serializing and deserializing a class that looked like this:
public class Appointment
{
public List<AppointmentRevision> Revisions { get; set; }
public AppointmentRevision CurrentRevision
{
get { return Revision.LastOrDefault(); }
}
public Appointment()
{
Revisions = new List<AppointmentRevision>();
}
}
public class AppointmentRevision
{
public List<Attendee> Attendees { get; set; }
}
When I serialized this, CurrentRevision was being serialized too. I'm not sure how, but when it was deserializing it was correctly keeping a single instance of the AppointmentRevision but creating duplicates in the Attendees list. The solution was to use the JsonIgnore attribute on the CurrentRevision property.
public class Appointment
{
public List<AppointmentRevision> Revisions { get; set; }
[JsonIgnore]
public AppointmentRevision CurrentRevision
{
get { return Revision.LastOrDefault(); }
}
public Appointment()
{
Revisions = new List<AppointmentRevision>();
}
}
How to apply ObjectCreationHandling.Replace to selected properties when deserializing JSON?
Turns out (I'm in 2019), you can set the list items in your constructor as you were doing in your question. I added the ObjectCreationHandling.Replace attribute above my declaration of the list, then serialising should replace anything stored in the list with the JSON.
i have recently stumbled upon a project(8-puzzle solver using A* alg) in which some codes are weird to me , because i have never seen the likes of it before .
what does this line mean ? what is this ?!
this[StateIndex]
whats this notation ? i cant undersand it at all !
i posted a sample of the class so that you can see it almost all together .
and one more question , is it not wrong to have a class implemented like StateNode? it used only a constructor to initialize its fields , and yet worst, declared them all public ! should he/she not have implemented Propertise for this task?
public enum Direction
{
Up = 1, Down = 2, Left = 3, Right = 4, UpUp = 5, DownDown = 6, LeftLeft = 7, RightRight = 8, Stop = 9
}
class StateNode
{
public int Parent;
public List<int> Childs;
public Direction Move;
public Direction ParentMove;
public byte[,] State;
public byte Depth;
public byte NullRow;
public byte NullCol;
public StateNode()
{ }
public StateNode(int NewParent, Direction NewMove, Direction ParentMove, byte NewDepth, byte NewNullRow, byte NewNullCol)
{
this.Parent = NewParent;
this.State = new byte[5, 5];
this.Move = NewMove;
this.ParentMove = ParentMove;
this.Depth = NewDepth;
this.NullRow = NewNullRow;
this.NullCol = NewNullCol;
this.Childs = new List<int>();
}
}
class StateTree : List<StateNode>
{
public static long MakedNodes;
public static long CheckedNodes;
public static byte MaxDepth;
public List<int> Successor1(int StateIndex)
{
List<int> RetNodes = new List<int>();
StateNode NewState = new StateNode();
//Up
if (this[StateIndex].NullRow + 1 <= 3 && this[StateIndex].ParentMove != Direction.Up)
{
NewState = ChangeItemState(this[StateIndex], StateIndex, Direction.Up, Direction.Down, Convert.ToByte(this[StateIndex].Depth + 1), this[StateIndex].NullRow, this[StateIndex].NullCol, Convert.ToByte(this[StateIndex].NullRow + 1), this[StateIndex].NullCol);
this.Add(NewState);
RetNodes.Add(this.Count - 1);
StateTree.MakedNodes++;
this[StateIndex].Childs.Add(this.Count - 1);
if (NewState.Depth > StateTree.MaxDepth)
StateTree.MaxDepth = NewState.Depth;
}
//Down
//Left
//Right
return RetNodes;
}
}
In your concrete case it's just access to the element, as it used inside the class that is derived from the List<T>
But it can be also indexer which enables index acces to your class object.
For example declare class like this:
public class ListWrapper
{
private List<int> list = ...
public int this[int index]
{
return list[index];
}
}
and after use it like
var lw = new ListWrapper();
//fill it with data
int a = lw[2]; //ACCESS WITH INDEX EVEN IF THE TYPE IS NOT COLLECTION BY ITSELF
this[StateIndex] is using the current class' indexer property. The indexer property is what allows you to access an element in a collection or list object as if it was an array. For instance:
List<string> strings = new List<string>();
strings.Add("Item 1");
strings.Add("Item 2");
strings.Add("Item 3");
string x = strings[0]; // Returns the first item in the list ("Item 1")
When you want to access the indexer property of your own class, however, you have to preface it with the this keyword. You'll notice that in your example, the StateTree class doesn't implement an indexer property, so that may be adding to your confusion. The reason it works is because StateTree inherits from List<StateNode> which does implement an indexer property.
But don't get confused between classes with indexer properties and arrays. Arrays are a completely different thing, though the syntax is similar. An array is a list of objects which can be accessed by an index. An indexer property is an unnamed property of a single object that acts as an array. So for instance, List<string> has an indexer property, so you can access the items it contains using the same syntax as an array index (as shown in the above example). However, you can still make an array of List<string> objects. So for instance:
List<string> strings1 = new List<string>();
strings1.Add("Item 1.1");
strings1.Add("Item 1.2");
List<string> strings2 = new List<string>();
strings2.Add("Item 2.1");
strings2.Add("Item 2.2");
List<string>[] stringsArray = new List<string>[] { strings1, strings2 };
object result;
result = stringsArray[0]; // Returns strings1
result = stringsArray[0][1]; // Returns "Item 1.2"
result = stringsArray[1][0]; // Returns "Item 2.1"
As far as StateNode goes, there's nothing technically wrong with it, and it's not unusual to have a constructor that initializes all the field values, but it's always better to use properties instead of public fields.
its Indexed Properties in C# .net .
you can check Tutorial : http://msdn.microsoft.com/en-us/library/aa288464(v=vs.71).aspx check here
this[StateIndex] is pointing to an element within the class. Because StateTree inherits from a List<T>, you have a collection that's accessible by index (in this case this[N] where N is the element's index.
this[StateIndex] is how you give a class and indexed property e.g
public class IndexedClass
{
private List<String> _content;
public IndexedClass()
{
_content = new List<String>();
}
public Add(String argValue)
{
_content.Add(argValue);
}
public string this[int index]
{
get
{
return _content[index];
}
set
{
_content[Index] = value;
}
}
}
so now you can do
IndexedClass myIndex = new IndexedClass();
myIndex.Add("Fred");
Console.Writeline(myIndex[0]);
myIndex[0] = "Bill";
Console.Writeline(myIndex[0]);
As for statenode if it's local to the class (a helper) then you could argue it as okay, I don't like it though, another ten minutes work it could be done properly. If it's public in the assembly, then it's not accpetable in my opinion. But that is an opinion.
I am working on a project where I need to keep track of:
5-6 Root items of just a string name
Each root item need to have multiple children of different identifier types (int, string, float, etc). All the children of one root will be the same type but each root will have different children types
user will need to be able to add/delete children from each root
i will later need to access each children individually and perform string manipulations and parsing when needed
I've thought about maybe using a dictionary where the Key is a string and Values are lists of objects. Or having a unique class for each root item and each class will include a List of children.
Does anyone have any good suggestions? I'm still quite new to OOP, please bear with me :)
Thanks!
public interface IRoot {}
public class RootItem<T> : IRoot
{
public string Name { get; set; }
public List<T> Children {get; set; }
}
And then keep a Dictionary<string, IRoot> to hold them all.
Dictionary<string, IRoot> hair = new Dictionary<string, IRoot>();
hair.Add(
new RootItem<int>()
{
Name = "None",
Children = new List<int>() {1, 2, 3, 4}
}
);
hair.Add(
new RootItem<decimal>()
{
Name = "None",
Children = new List<decimal>() {1m, 2m, 3m, 4m}
}
);
How about a generic class with a List<T> to contain the children:
public class Root<T>
{
private List<T> children = null;
public Root(string name)
{
Name = name;
}
public string Name { get; set; }
public List<T> Children
{
get
{
if (children == null)
{
children = new List<T>();
}
return children;
}
}
}
Root<int> intRoot = new Root<int>("IntRoot");
intRoot.Children.Add(23);
intRoot.Children.Add(42);
Root<string> stringRoot = new Root<string>("StringRoot");
stringRoot.Children.Add("String1");
stringRoot.Children.Add("String2");
stringRoot.Children.Add("String3");
stringRoot.Children.Add("String4");
If you want to hold all the roots in one object, you could write your own class or use a Tuple:
var rootGroup = Tuple.Create(intRoot, stringRoot);
// intRoot is accessible as rootGroup.Item1
// stringRoot is accessible as rootGroup.Item2
Sounds like Dictionary<string, Tuple<type1, type 2, etc>> is a good candidate.
The key will be the string(root). The children to the root is a Tuple. We can add items to tuple. Thanks for pointing thisout.
Good starting point on Tuple
Here's one way to go about it. There's a lot of casting that needs to happen, but it gets the job done:
static void Main(string[] args)
{
Dictionary<string, IRootCollection> values = new Dictionary<string, IRootCollection>();
values["strings"] = new RootCollection<string>();
(values["strings"] as RootCollection<string>).Add("foo");
(values["strings"] as RootCollection<string>).Add("bar");
values["ints"] = new RootCollection<int>();
(values["ints"] as RootCollection<int>).Add(45);
(values["ints"] as RootCollection<int>).Add(86);
}
interface IRootCollection { }
class RootCollection<T> : List<T>, IRootCollection { }