Given a node like
class Node
{
public int Val { get; set; }
public Node Parent { get; set; }
public List<Node> Children { get; set; } = new List<Node>();
/// <summary>
/// Sum of values in descendant nodes
/// </summary>
public int DescendantsSum { get; set; } = 0;
/// <summary>
/// Sum of values in tree whose root is this node
/// </summary>
public int TreeSum { get { return Val + DescendantsSum; } }
}
and a tree of Nodes with Vals that have been set, what I'm trying to do is what is described in the summary of the following method I wrote
/// <summary>
/// Given a tree like
///
/// Val=100
/// \
/// Val=200
/// / \
/// / Val=100
/// Val=100
/// / \
/// Val=500 Val=600
///
/// set a field for each node showing the sum of the values
/// in the subtree whose root is that node, making it into
///
/// Val=100
/// Sum=1600
/// \
/// Val=200
/// Sum=1500
/// / \
/// / Val=100
/// / Sum=100
/// Val=100
/// Sum=1200
/// / \
/// Val=500 Val=600
/// Sum=500 Sum=600
///
/// </summary>
static void SetSums(Node[] nodes)
{
foreach(var leaf in nodes.Where(node => node.Children.Count == 0))
for(var cur = leaf; cur.Parent != null; cur = cur.Parent)
cur.Parent.DescendantsSum += cur.TreeSum;
}
However, this is leading to incorrectly large values like 3400 where it should be 1600. I've thought over my algorithm and I can't see where it is flawed. Any hints?
When you are working with trees it's sometimes easier to go from the top to the buttom and not the other way as you did.
I think this should work for your needs:
public class Node
{
public int Val { get; set; }
public Node Parent { get; set; }
public List<Node> Children { get; set; } = new List<Node>();
/// <summary>
/// Sum of values in descendant nodes
/// </summary>
public int DescendantsSum
{
get
{
var sum = 0;
foreach(var child in Children)
{
sum += child.TreeSum;
//You can do this instead
//sum += child.Val;
//sum += child.DescendantsSum;
}
return sum;
}
}
/// <summary>
/// Sum of values in tree whose root is this node
/// </summary>
public int TreeSum { get { return Val + DescendantsSum; } }
}
Or by using LINQ:
public int DescendantsSum
{
get
{
return Children.Sum(child => child.TreeSum);
}
}
I'm not going to discuss the top-down vs bottom-up algorithms. You have chosen the bottom-up, fine, so where is the flaw?
Consider the following simple tree:
child1
\
parent - grandparent
/
child2
Your algorithm will do:
parent.DescendantsSum += child1.TreeSum;
grandparent.DescendantsSum += parent.TreeSum;
parent.DescendantsSum += child2.TreeSum;
grandparent.DescendantsSum += parent.TreeSum;
As you can see, parent.TreeSum is added twice to the grandparent.DescendantsSum which leads to the incorrect results.
Since the DescendantsSum is effectively the sum of the Val of all descendant nodes, one way to fix the algorithm is to process all nodes and add the node Val to each node parent.
static void SetSums(Node[] nodes)
{
foreach (var node in nodes)
node.DescendantsSum = 0;
foreach (var node in nodes)
for (var parent = node.Parent; parent != null; parent = parent.Parent)
parent.DescendantsSum += node.Val;
}
You need a recursive function.
This works fine:
class NodeTest
{
public static void Run()
{
var root = new Node() { Val = 1 };
var a1 = new Node() { Val = 2 };
var a2 = new Node() { Val = 3 };
var a11 = new Node() { Val = 4 };
var a12 = new Node() { Val = 5 };
var a13 = new Node() { Val = 6 };
var a21 = new Node() { Val = 7 };
var a22 = new Node() { Val = 8 };
a1.Children.AddRange(new Node[] { a11, a12, a13 });
a2.Children.AddRange(new Node[] { a21, a22 });
root.Children.AddRange(new Node[] { a1, a2 });
Console.WriteLine(root.DescendantsSum);
Console.WriteLine(root.TreeSum);
Console.WriteLine();
Console.WriteLine(a1.DescendantsSum);
Console.WriteLine(a1.TreeSum);
}
}
class Node
{
public int Val { get; set; }
public List<Node> Children { get; set; }
/// <summary>
/// Sum of values in descendant nodes
/// </summary>
public int DescendantsSum
{
get
{
return TreeSum - Val;
}
}
/// <summary>
/// Sum of values in tree whose root is this node
/// </summary>
public int TreeSum
{
get
{
return GetTreeSum(this);
}
}
public Node()
{
Children = new List<Node>();
}
private int GetTreeSum(Node node)
{
int result = 0;
if (node.Children.Count > 0)
{
result += node.Val;
node.Children.ForEach(c => { result += GetTreeSum(c); });
}
else
result += node.Val;
return result;
}
}
Related
How to get a sum of all the results.parent1? I am using linqpad. the dump function puts it in a table but i would like to printed via console.write. How can i achieve the same?
void Main()
{
List<parent> a = new List<parent>();
a.Add(new parent(2, true));
a.Add(new parent(3, false));
a.Add(new parent(4, true));
List<parent> results = a.FindAll(
delegate (parent p)
{
return p.child1 == true;
});
if (results.Count > 0)
{
//how do i find the sum of all the results.parent1?
results.Dump();
Console.Write("sum of all the results.parent1? ");
}
}
/// <summary>
/// This file holds all user defined indicator methods.
/// </summary>
public class parent
{
int v;
public parent(double d, bool b)
{
this.parent1 = d;
this.child1 = b;
}
public double parent1 { get; set; }
public bool child1 { get; set; }
}
I've been looking for a way to implement both A* and Dijkstra to be able to get the shortest path and start to finish.
I retrieve a list of nodes and edges from a SQL database put the items into two dictionaries (Nodes and Edges) with the node/edge id as the keys.
The start (148309) and end (1483093) node I used to test, returns a result, but it visits 21 other nodes and should return 3 nodes (108.75m)
Attempting to use the pseduo code in the links below, I've managed to make it find the path but I'm struggling with the backtracing to get the actual shortest path it took. The links below don't mention this within their examples.
https://www.csharpstar.com/dijkstra-algorithm-csharp/
https://www.programmingalgorithms.com/algorithm/dijkstra's-algorithm/
https://www.dotnetlovers.com/article/234/dijkstras-shortest-path-algorithm
Objects
public class Node
{
public Node()
{
Edges = new Dictionary<long, Edge>();
}
public long Id { get; set; }
public double Latitude { get; set; }
public double Longitude { get; set; }
/// <summary>
/// The edges coming out of this node.
/// </summary>
public Dictionary<long, Edge> Edges { get; set; }
public double DistanceFromStart { get; set; }
public double DistanceToEnd { get; set; }
public bool Visited { get; set; }
/// <summary>
/// Specified the distance in KM between this node and the
/// specified node using their lat/longs.
/// </summary>
/// <param name="node"></param>
/// <returns></returns>
public double DistanceTo(ref Node node)
{
return DistanceHelper.DistanceTo(this, node);
}
}
public class Edge
{
public long UID { get; set; }
public long StartNodeId { get; set; }
public long EndNodeId { get; set; }
public double Distance { get; set; }
public Node EndNode { get; set; }
}
public class SPResult
{
public double Distance { get; set; }
public long[] Nodes { get; set; }
public long[] Edges { get; set; }
}
Code so far.
public static Graph graph = new Graph();
static void Main(string[] args)
{
Console.WriteLine("Starting");
//Loads the nodes and edges from a SQL database.
LoadInfrastructure(3);
var res = graph.GetShortestPathDijkstra(1483099, 1483093);
//var res = graph.GetShortestPathDijkstra(1483129, 3156256);
Console.WriteLine("Done. Press any key to exit.");
Console.ReadKey();
}
public class Graph
{
public Graph()
{
Nodes = new Dictionary<long, Node>();
Edges = new Dictionary<long, Edge>();
}
Dictionary<long, Node> Nodes { get; set; }
Dictionary<long, Edge> Edges { get; set; }
Dictionary<long, double> queue;
Stopwatch stopwatch = new Stopwatch();
public void AddNode(Node n)
{
if (Nodes.ContainsKey(n.Id))
throw new Exception("Id already in graph.");
Nodes.Add(n.Id, n);
}
public void AddEdge(Edge e)
{
if (Edges.ContainsKey(e.UID))
throw new Exception("Id already in graph.");
e.EndNode = Nodes[e.EndNodeId];
Edges.Add(e.UID, e);
Nodes[e.StartNodeId].Edges.Add(e.UID, e);
}
public SPResult GetShortestPathDijkstra(long start, long end)
{
return GetShortestPathDijkstra(Nodes[start], Nodes[end]);
}
public SPResult GetShortestPathDijkstra(Node start, Node end)
{
if (!Nodes.ContainsKey(start.Id))
throw new Exception("Start node missing!");
if (!Nodes.ContainsKey(end.Id))
throw new Exception("End node missing!");
Console.WriteLine($"Finding shortest path between {start.Id} and {end.Id}...");
ResetNodes(null);
stopwatch.Restart();
Node current = start;
current.DistanceFromStart = 0;
queue.Add(start.Id, 0);
while (queue.Count > 0)
{
long minId = queue.OrderBy(x => x.Value).First().Key;
current = Nodes[minId];
queue.Remove(minId);
if (minId == end.Id)
{
current.Visited = true;
break;
}
foreach (var edge in current.Edges.OrderBy(ee => ee.Value.Distance))
{
var endNode = edge.Value.EndNode;
if (endNode.Visited)
continue;
double distance = current.DistanceFromStart + edge.Value.Distance;
if (queue.ContainsKey(endNode.Id))
{
if (queue[endNode.Id] > distance)
{
queue[endNode.Id] = endNode.Id;
Nodes[endNode.Id].DistanceFromStart = distance;
}
}
else
{
Nodes[endNode.Id].DistanceFromStart = distance;
queue.Add(endNode.Id, distance);
}
}
current.Visited = true;
}
stopwatch.Stop();
Console.WriteLine($"Found shortest path between {start.Id} and {end.Id} in {stopwatch.ElapsedMilliseconds}ms.");
Debug.WriteLine($"Found shortest path between {start.Id} and {end.Id} in {stopwatch.ElapsedMilliseconds}ms.");
**//Get path used.**
var rr = Nodes.Values.Where(nn => nn.Visited).OrderBy(nn => nn.DistanceFromStart).ToList();
return null;
}
public SPResult GetShortestPathAstar(long start, long end)
{
return GetShortestPathAstar(Nodes[start], Nodes[end]);
}
public SPResult GetShortestPathAstar(Node start, Node end)
{
ResetNodes(end);
start.DistanceFromStart = 0;
throw new NotImplementedException();
}
private void ResetNodes(Node endNode)
{
queue = new Dictionary<long, double>();
foreach (var node in Nodes)
{
node.Value.DistanceFromStart = double.PositiveInfinity;
node.Value.Visited = false;
if (endNode != null)
node.Value.DistanceToEnd = node.Value.DistanceTo(ref endNode);
}
}
}
I managed to use a YouTube video to go through the pseudocode and implement both Dijkstra and A* algorithms.
https://www.youtube.com/watch?v=nhiFx28e7JY
https://www.youtube.com/watch?v=mZfyt03LDH4
Program.cs (Snippet)
LoadInfrastructureFromSQL();
var resA5 = graph.GetShortestPathAstar(startId, endId);
Node
public class Node
{
public Node()
{
}
public Node(long id, double lat, double lon) : this()
{
Id = id;
Latitude = lat;
Longitude = lon;
}
public long Id { get; set; }
public double Latitude { get; set; }
public double Longitude { get; set; }
public double Gcost { get; set; }
public double Hcost { get; set; }
public double Fcost => Gcost + Hcost;
public Node Parent { get; set; }
/// <summary>
/// The edges coming out of this node.
/// </summary>
public Dictionary<long, Edge> Edges { get; set; }
public void AddEdges(Edge e)
{
if (Edges == null)
Edges = new Dictionary<long, Edge>();
if (Edges.ContainsKey(e.UID))
throw new Exception($"Edge id {e.UID} already exists.");
Edges.Add(e.UID, e);
}
public double DistanceTo(Node point)
{
double p = 0.017453292519943295;
double a = 0.5 - Math.Cos((point.Latitude - Latitude) * p) / 2 + Math.Cos(Latitude * p) * Math.Cos(point.Latitude * p) * (1 - Math.Cos((point.Longitude - Longitude) * p)) / 2;
return 12742 * Math.Asin(Math.Sqrt(a));
}
}
Edge
public class Edge
{
public Edge()
{
}
public Edge(long uid, long id, double distance)
{
UID = uid;
WayId = id;
Distance = distance;
}
public Edge(long uid, long id, double distance, long startNode, long endNode) : this(uid, id, distance)
{
StartNodeId = startNode;
EndNodeId = endNode;
}
/// <summary>
/// Unique way id for every single edge.
/// </summary>
public long UID { get; set; }
/// <summary>
/// Duplicate edges will share the same WayId i.e. if the way is bi-directional.
/// </summary>
public long WayId { get; set; }
public long StartNodeId { get; set; }
public long EndNodeId { get; set; }
public Node EndNode { get; set; }
public double Distance { get; set; }
}
Result (Optional)
public class SPResult
{
public double Distance { get; set; }
public Node[] Nodes { get; set; }
public long NodesChecked { get; set; }
public Edge[] Edges { get; set; }
public long CalculationTime { get; set; }
}
Graph and Algorithm
//Routing algorithm taken from https://www.youtube.com/watch?time_continue=5&v=-L-WgKMFuhE
public class Graph
{
public Graph()
{
Nodes = new Dictionary<long, Node>();
Edges = new Dictionary<long, Edge>();
}
Dictionary<long, Node> Nodes { get; set; }
Dictionary<long, Edge> Edges { get; set; }
Dictionary<long, Node> open;
Dictionary<long, Node> closed;
Stopwatch stopwatch = new Stopwatch();
public void AddNode(Node n)
{
if (Nodes.ContainsKey(n.Id))
throw new Exception("Id already in graph.");
Nodes.Add(n.Id, n);
}
public void AddEdge(Edge e)
{
e.EndNode = Nodes[e.EndNodeId];
Edges.Add(e.UID, e);
Nodes[e.StartNodeId].AddEdges(e);
}
public Node FindClosestNode(double lat, double lon, int radius)
{
Node n = new Node();
n.Latitude = lat;
n.Longitude = lon;
return FindClosestNode(n, radius);
}
public Node FindClosestNode(Node node, int radius)
{
Console.WriteLine($"Finding closest node [Latitude: {Math.Round(node.Latitude, 6)}, Longitude:{Math.Round(node.Longitude, 6)}]...");
Stopwatch sw = new Stopwatch();
sw.Start();
var res = Nodes.Select(x => new { Id = x.Key, Distance = x.Value.DistanceTo(node) }).Where(nn => nn.Distance < radius).OrderBy(x => x.Distance).FirstOrDefault();
if (res != null)
{
Debug.WriteLine($"Found nearest node in {sw.ElapsedMilliseconds}ms [{res.Id}]");
return Nodes[res.Id];
}
Debug.WriteLine($"No nearest node {sw.ElapsedMilliseconds}ms [{res.Id}]");
return null;
}
#region ROUTING
public async Task<SPResult> GetShortestPathDijkstra(long start, long end)
{
return await GetShortestPathDijkstra(Nodes[start], Nodes[end]);
}
public async Task<SPResult> GetShortestPathDijkstra(Node start, Node end)
{
if (!Nodes.ContainsKey(start.Id))
throw new Exception("Start node missing!");
if (!Nodes.ContainsKey(end.Id))
throw new Exception("End node missing!");
Console.WriteLine($"Finding Dijkstra shortest path between {start.Id} and {end.Id}...");
ResetNodes(null);
stopwatch.Restart();
open.Add(start.Id, start);
start.Gcost = 0;
Node current = start;
while (true)
{
long lowest = open.OrderBy(qq => qq.Value.Fcost).FirstOrDefault().Key;
current = Nodes[lowest];
open.Remove(lowest);
closed.Add(lowest, current);
if (current.Id == end.Id)
break;
foreach (var neigh in current.Edges)
{
Node edgeEnd = neigh.Value.EndNode;
if (closed.ContainsKey(edgeEnd.Id))
continue;
double distance = current.Gcost + neigh.Value.Distance;
if (distance < edgeEnd.Gcost || !open.ContainsKey(edgeEnd.Id))
{
edgeEnd.Gcost = distance;
edgeEnd.Parent = current;
if (!open.ContainsKey(edgeEnd.Id))
open.Add(edgeEnd.Id, edgeEnd);
}
}
}
stopwatch.Stop();
Console.WriteLine($"Found shortest path between {start.Id} and {end.Id} in {stopwatch.ElapsedMilliseconds}ms.");
Debug.WriteLine($"Found shortest path between {start.Id} and {end.Id} in {stopwatch.ElapsedMilliseconds}ms.");
SPResult spr = new SPResult();
spr.CalculationTime = stopwatch.ElapsedMilliseconds;
spr.Distance = current.Gcost;
var traceback = Traceback(current);
spr.Nodes = traceback.Item1;
spr.Edges = traceback.Item2;
spr.NodesChecked = closed.Count + open.Count;
return spr;
}
public async Task<SPResult> GetShortestPathAstar(long start, long end)
{
return await GetShortestPathAstar(Nodes[start], Nodes[end]);
}
public async Task<SPResult> GetShortestPathAstar(Node start, Node end)
{
if (!Nodes.ContainsKey(start.Id))
throw new Exception("Start node missing!");
if (!Nodes.ContainsKey(end.Id))
throw new Exception("End node missing!");
Console.WriteLine($"Finding A* shortest path between {start.Id} and {end.Id}...");
ResetNodes(end);
stopwatch.Restart();
start.Gcost = 0;
Node current = start;
open.Add(start.Id, current);
while (true)
{
if (open.Count() == 0)
return null;
long lowest = open.OrderBy(qq => qq.Value.Fcost).FirstOrDefault().Key;
current = Nodes[lowest];
open.Remove(lowest);
closed.Add(lowest, current);
if (current.Id == end.Id)
break;
foreach (var neigh in current.Edges)
{
Node edgeEnd = neigh.Value.EndNode;
if (closed.ContainsKey(edgeEnd.Id))
continue;
double distance = current.Gcost + neigh.Value.Distance;
if (distance < (edgeEnd.Gcost) || !open.ContainsKey(edgeEnd.Id))
{
edgeEnd.Gcost = distance;
edgeEnd.Hcost = current.DistanceTo(end);
edgeEnd.Parent = current;
if (!open.ContainsKey(edgeEnd.Id))
open.Add(edgeEnd.Id, edgeEnd);
}
}
}
stopwatch.Stop();
Console.WriteLine($"Found shortest path between {start.Id} and {end.Id} in {stopwatch.ElapsedMilliseconds}ms.");
Debug.WriteLine($"Found shortest path between {start.Id} and {end.Id} in {stopwatch.ElapsedMilliseconds}ms.");
SPResult spr = new SPResult();
spr.CalculationTime = stopwatch.ElapsedMilliseconds;
spr.Distance = current.Gcost;
var traceback = Traceback(current);
spr.Nodes = traceback.Item1;
spr.Edges = traceback.Item2;
spr.NodesChecked = closed.Count + open.Count;
return spr;
}
private (Node[],Edge[]) Traceback(Node current)
{
Stopwatch sw = new Stopwatch();
sw.Start();
List<Node> nodes = new List<Node>();
List<Edge> edges = new List<Edge>();
nodes.Add(current);
while (current.Parent != null)
{
edges.Add(current.Parent.Edges.FirstOrDefault(ee => ee.Value.EndNodeId == current.Id).Value);
current = current.Parent;
nodes.Add(current);
}
Debug.WriteLine($"Traceback in {sw.ElapsedMilliseconds}ms.");
return nodes.Reverse<Node>().ToArray();
}
private void ResetNodes(Node endNode)
{
open = new Dictionary<long, Node>();
closed = new Dictionary<long, Node>();
foreach (var node in Nodes)
{
node.Value.Gcost = double.PositiveInfinity;
node.Value.Hcost = double.PositiveInfinity;
}
}
#endregion
}
I have a class with fields - Id , name, company and another 29 fields.
public class Employee
{
[XmlAttribute("textbox1")]
public int Id { get; set; }
[XmlAttribute("textbox11")]
public string Name { get; set; }
[XmlAttribute("textbox21")]
public string Company { get; set; }
[XmlAttribute("textbox22")]
public bool Val1 { get; set; }
[XmlAttribute("textbox23")]
public bool Val2 { get; set; }
public bool TestSomething{get;set;}
}
public class ParseData()
{
List<Employee> employee = new List<Employee>();
XmlSerialiser serializer = new XmlSerializer();
using(FileStream stream = new FileStream("test.xml", FileMode.Open))
{
employees = (Employee)serializer.Deserialize(stream);
}
//Todo: Add the new calculated value TestSomething
}
I'm deserialising the values from the xml data ( which has around 100 employees).
Now I have a new field 'TestSomething' which is not deserialised but will be result of deserialised value as shown below. Is there a way I could add calculated values to the existing list employees ?
foreach(var i in employees)
{
employee.TestSomething = (Val1 == true) ? Val1 : Val2;
}
Any suggestion on this will be appreciated.
The code snippets below are extension methods I use to serialize and deserialize xml strings. Note these need to be put in a static class and referenced in the class for use.
/// <summary>
/// Serializes the object to xml string.
/// </summary>
/// <returns>xml serialization.</returns>
public static string SerializeToXml<T>(this T instance)
where T : class, new()
{
string result;
var format = new XmlSerializer(typeof(T));
using (var strmr = new StringWriter())
{
format.Serialize(strmr, instance);
result = strmr.ToString();
}
return result;
}
/// <summary>
/// Deserializes xml serialized objects.
/// </summary>
/// <param name="xmlDocument">serialized string.</param>
/// <param name="result">out parameter.</param>
/// <returns>Instance object.</returns>
public static bool TryParseXml<T>(this string xmlDocument, out T result)
where T : class, new()
{
result = null;
if (string.IsNullOrWhiteSpace(xmlDocument))
{
return false;
}
try
{
using (TextReader str = new StringReader(xmlDocument))
{
var format = new XmlSerializer(typeof(T));
XmlReader xmlReader = XmlReader.Create(str);
if (format.CanDeserialize(xmlReader))
{
result = format.Deserialize(xmlReader) as T;
}
}
}
catch (InvalidOperationException)
{
return false;
}
return !(result is null);
}
In practice you would have a class of some type that has properties that you would like to store to a disk or database etc. Lets say I have a class:
public class MyPoint
{
public double X { get; set;}
public double Y { get; set;}
}
If I wanted to store a list of MyPoint without much heavy lifting I could serialize the class directly using the SerializeToXml method above.
var myPoints = new List<MyPoint>{new MyPoint{ X= 1, Y = 2}, new MyPoint{X = 3, Y = 4}};
var xmlString = myPoints.SerializeToXml();
Everything is fine and dandy, my info is saved as xml in some file somewhere. But then my boss says, "Dang, sorry about this but we need a Z value now that is computed from the X and Y of each using Z = X * X + Y * Y."
Adding properties to the serialized class isn't a problem (taking properties out is!!
The serializer will try to assign a value to a property that doesn't exist and throw an exception.). But in this case we don't need to worry. I go to the original MyPoint class and add a Z.
public class MyPoint
{
public double X { get; set;}
public double Y { get; set;}
public double Z { get; set;} // <---- Here
}
Now when I parse the xml I will get classes with the new property. Using the TryParseXml I get my list of points.
// assume I have a string already from the xml document to use.
List<MyPoint> points = null;
if(serializedPoints.TryParse(out points))
{
foreach(var point in points)
{
point.Z = X * X + Y * Y;
}
}
var serializedPointsWithZ = points.SerializeToXml();
Now serializedPointsWithZ is just a string that can be written to a file etc.
Hello there :) I'm having a problem when cloning an object that contains other objects and lists in winForm.
I want to Clone an Object of Type Structure the classes are provided below
first of all i have tried Shallow Clone
public Structure Clone()
{
return this.MemberwiseClone() as Structure;
}
put it didn't work so i searched https://stackoverflow.com/ and i did a deep clone
Deep cloning objects
and this
How do you do a deep copy of an object in .NET (C# specifically)?
public static T DeepClone<T>(T obj)
{
using (var ms = new MemoryStream())
{
var formatter = new BinaryFormatter();
formatter.Serialize(ms, obj);
ms.Position = 0;
return (T) formatter.Deserialize(ms);
}
}
The Problem that I'm having is i am taking a backup copy of an object
var backup=DeepClone<Structure>(this.sched); //sched is Structure Object
and then changing this.sched the backup is changed :(
the structre of my classes is:
[Serializable]
public class Sub
{
string name;
int studentsNumber;
int unassaignedStudent;
public Sub(string name, int number)
{
this.name = name;
this.studentsNumber = number;
this.unassaignedStudent = number;
}
public Subject()
{
this.name = "";
this.studentsNumber = 0;
this.unassaignedStudent = 0;
}
public bool Assigne(int count)
{
//stuff
}
public Sub Clone()
{
return this.MemberwiseClone() as Sub;
}
}
[Serializable]
class Room
{
string name;
int studentsNumber;
int full;
private int freeSeats;
List<Sub> subjects;
/// <summary>
/// the list of subjects
/// </summary>
internal List<Sub> Subjects
{
get { return subjects; }
set { subjects = value; }
}
Dictionary<Subject, int> variations;
public Room(string name, int number)
{
this.name = name;
this.studentsNumber = number;
this.full = 0;
this.subjects = new List<Subject>();
this.variations = new Dictionary<Subject, int>();
this.freeSeats = number;
}
public Room(int number)
{
this.studentsNumber = number;
this.full = 0;
this.subjects = new List<Subject>();
this.variations = new Dictionary<Subject, int>();
this.freeSeats = number;
}
public Room()
{
this.name = "R" + count.ToString();
count++;
this.studentsNumber = 0;
this.full = 0;
this.subjects = new List<Sub>();
this.variation= new Dictionary<Sub, int>();
this.freeSeats = 0;
}
public bool addSubject(Sub sbj)
{
//also stuff
}
public bool addPartialSubject(Sub sbj)
{
//stuff
// return false;
}
public Room Clone()
{
return this.MemberwiseClone() as Room;
}
}
[Serializable]
class Period
{
List<Room> rooms;
int conflicts;
List<Sub> subjects;
internal List<Sub> Subjects
{
get { return subjects; }
set { subjects = value; }
}
/// <summary>
/// Create an instance of class Period
/// </summary>
/// <param name="rooms">the rooms in this Period</param>
public Period(List<Room> rooms)
{
this.conflicts = 0;
this.rooms = rooms;
subjects = new List<Subject>();
fillSubjects(ref rooms, ref subjects);
}
public Period()
{
this.conflicts = 0;
this.rooms = null;
subjects = new List<Subt>();
freeSeats = 0;
}
/// <summary>
/// Fill the subjects in the rooms to the list of subjects
/// </summary>
/// <param name="rooms">referance to the list of the rooms</param>
/// <param name="subjects">referance to the list of the subjects</param>
private void fillSubjects(ref List<Room> rooms, ref List<Sub> subjects)
{
foreach (var room in rooms)
{
foreach (var subject in room.Subjects)
{
if (!subjects.Exists(s => s.Name == subject.Name))
subjects.Add(subject);
}
}
}
/// <summary>
/// Adds the given subject to the period if there is a place in any room
/// </summary>
/// <param name="s">the subject to add</param>
/// <returns>true if there is space for this subject and added, otherwise false</returns>
public bool AddSubject(Sub s)
{
foreach (var room in rooms)
{
if (room.addSubject(s))
{
//stuff
}
else
if (room.addPartialSubject(s))
{
//stuff
}
}
return false;
}
private int CalculateConflictions(Sub s)
{
//also a lot of stuff
}
}
[Serializable]
class Structure:IDisposable
{
int days;
/// <summary>
/// the number of days in the Schedual
/// </summary>
public int Days
{
get { return days; }
set { days = value; }
}
int periods;
Period[,] schedualArray;
List<Room> rooms;
internal List<Room> Rooms
{
get { return rooms; }
set { rooms = value; }
}
/// <summary>
/// Creates an instance of the Structure object
/// </summary>
/// <param name="rooms">a list of the rooms in the Schedual</param>
public Structure(int days, int periods,List<Room> rooms)
{
this.days = days;
this.periods = periods;
this.rooms=rooms;
this.schedualArray = new Period[days, periods];
this.subjectCount = 0;
for (int i = 0; i < days; i++)
{
for (int j = 0; j < periods; j++)
{
schedualArray[i, j] = new Period(CloneList(ref rooms)); //here i cloned the list to be in the safe side and it didn't work also
}
}
}
public Structure()
{
this.days = 0;
this.totalEval = Int32.MaxValue;
this.periods = 0;
this.rooms = null;
this.subjectCount = 0;
this.schedualArray = null;
}
internal bool AddSubject(Sub subject, int day, int period)
{
//add the subject into inner lists (room)
}
public void PrintStruct()
{
for (int i = 0; i < days; i++)
{
for (int j = 0; j < periods; j++)
{
foreach (var subject in schedualArray[i, j].Subjects)
{
Console.Write("\t\t");
}
Console.Write("\t\t");
}
Console.WriteLine();
}
}
public Structure Clone()
{
return this.MemberwiseClone() as Structure;
}
public List<Room> CloneList(ref List<Room> rooms)
{
var lst = new List<Room>();
foreach (var room in rooms)
{
lst.Add(DeepClone<Room>(room));
}
return lst;
}
internal void RemoveSubject(Sub subject)
{
//..................
}
#region IDisposable Members
public void Dispose()
{
GC.Collect(g, GCCollectionMode.Forced);
}
#endregion
}
I don't really now what are the details of the cloning process but my requirement is to clone the entire object with the successive objects in the structure and hirarachy of the object and the complete items that the list points to not only there references
Please Can anyone help me please I'm really lost:(, thanks in advance to everyone interested in helping me :) Yaser
EDIT when using the method #WiiMaxx
Structure backup=XamlClone(this.sched);
private Structure XamlClone(Structure s)
{
//First Step
// create a XAML string
string stCopie = XamlWriter.Save(s);
//Secound Step
// convert him back to an Object of YourTyp
return XamlReader.Load(XmlReader.Create(new StringReader(stCopie))) as Structure;
}
but the inner period[,] is cloned as null
Can you please help me #WiiMaxx
Edit 2.0
i have also checked this article about deep cloning in 3 methods and i think i have circular references in my code that is why this isn't working for me
http://blog.nuclex-games.com/mono-dotnet/fast-deep-cloning/
End Edit
Ok now it should really work
(i deleted also my old solution because it was totally wrong for your needs)
Sub.cs
public class Sub: ICloneable
{
struct datenStruct
{
internal int studentsNumber;
internal int unassaignedStudent;
internal string name;
}
private datenStruct USE;
int studentsNumber;
public string Name
{
get { return USE.name; }
set { USE.name = value; }
}
private Sub(datenStruct struc)
{
this.USE = struc;
}
public Sub(string name, int number)
{
this.USE = new datenStruct();
this.USE.name = name;
this.USE.studentsNumber = number;
this.USE.unassaignedStudent = number;
}
public bool Assigne(int count)
{
//stuff
return true;
}
public object Clone()
{
var copie = new datenStruct();
copie.name = USE.name;
copie.unassaignedStudent = USE.unassaignedStudent;
copie.studentsNumber = USE.studentsNumber;
return new Sub(copie);
}
}
Room.cs
public class Room: ICloneable
{
struct datenStruct
{
internal int studentsNumber;
internal int full;
internal string name;
internal int freeSeats;
internal List<Sub> subjects;
internal Dictionary<Sub, int> variations;
}
private datenStruct USE;
/// <summary>
/// the list of subjects
/// </summary>
internal List<Sub> Subjects
{
get { return USE.subjects; }
set { USE.subjects = value; }
}
public Room(string name, int number)
{
this.USE = new datenStruct();
this.USE.name = name;
this.USE.studentsNumber = number;
this.USE.full = 0;
this.USE.subjects = new List<Sub>();
this.USE.variations = new Dictionary<Sub, int>();
this.USE.freeSeats = number;
}
public Room(int number)
{
this.USE = new datenStruct();
this.USE.studentsNumber = number;
this.USE.full = 0;
this.USE.subjects = new List<Sub>();
this.USE.variations = new Dictionary<Sub, int>();
this.USE.freeSeats = number;
}
private Room(datenStruct struc)
{
USE = struc;
}
public bool addSubject(Sub sbj)
{
//also stuff
return false;
}
public bool addPartialSubject(Sub sbj)
{
//stuff
return false;
}
public object Clone()
{
var copie = new datenStruct();
copie.studentsNumber = USE.studentsNumber;
copie.full = USE.full;
copie.freeSeats = USE.freeSeats;
var SubListCopie = new List<Sub>();
foreach (Sub origSub in USE.subjects)
SubListCopie.Add((Sub)origSub.Clone());
copie.subjects = SubListCopie;
var SubDictCopie = new Dictionary<Sub, int>();
foreach (KeyValuePair<Sub, int> KvP in USE.variations)
SubDictCopie.Add((Sub)KvP.Key.Clone(),KvP.Value);
copie.variations = SubDictCopie;
return new Room(copie);
}
}
Period.cs
public class Period: ICloneable
{
struct datenStruct
{
internal List<Room> rooms;
internal List<Sub> subjects;
internal string name;
internal int conflicts;
}
private datenStruct USE;
internal List<Sub> Subjects
{
get { return USE.subjects; }
set { USE.subjects = value; }
}
/// <summary>
/// Create an instance of class Period
/// </summary>
/// <param name="rooms">the rooms in this Period</param>
public Period(List<Room> rooms)
{
this.USE.conflicts = 0;
this.USE.rooms = rooms;
this.USE.subjects = new List<Sub>();
fillSubjects(ref USE.rooms, ref USE.subjects);
}
private Period(datenStruct struc)
{
USE = struc;
}
/// <summary>
/// Fill the subjects in the rooms to the list of subjects
/// </summary>
/// <param name="rooms">referance to the list of the rooms</param>
/// <param name="subjects">referance to the list of the subjects</param>
private void fillSubjects(ref List<Room> rooms, ref List<Sub> subjects)
{
foreach (var room in rooms)
{
foreach (var subject in room.Subjects)
{
if (!subjects.Exists(s => s.Name == subject.Name))
subjects.Add(subject);
}
}
}
/// <summary>
/// Adds the given subject to the period if there is a place in any room
/// </summary>
/// <param name="s">the subject to add</param>
/// <returns>true if there is space for this subject and added, otherwise false</returns>
public bool AddSubject(Sub s)
{
foreach (var room in USE.rooms)
{
if (room.addSubject(s))
{
//stuff
}
else
if (room.addPartialSubject(s))
{
//stuff
}
}
return false;
}
private int CalculateConflictions(Sub s)
{
//also a lot of stuff
return 1;
}
public object Clone()
{
var copie = new datenStruct();
copie.name = USE.name;
copie.conflicts = USE.conflicts;
var RoomListCopie = new List<Room>();
foreach (Room origSub in USE.rooms)
RoomListCopie.Add((Room)origSub.Clone());
copie.rooms = RoomListCopie;
var SubListCopie = new List<Sub>();
foreach (Sub origSub in USE.subjects)
SubListCopie.Add((Sub)origSub.Clone());
copie.subjects = SubListCopie;
return new Period(copie);
}
}
Structure.cs
public class Structure : IDisposable,ICloneable
{
struct datenStruct
{
internal int days;
internal int subjectCount;
internal int periods;
internal Period[,] schedualArray;
internal List<Room> rooms;
}
private datenStruct USE;
/// <summary>
/// the number of days in the Schedual
/// </summary>
public int Days
{
get { return USE.days; }
set { USE.days = value; }
}
internal List<Room> Rooms
{
get { return USE.rooms; }
set { USE.rooms = value; }
}
/// <summary>
/// Creates an instance of the Structure object
/// </summary>
/// <param name="rooms">a list of the rooms in the Schedual</param>
public Structure(int days, int periods, List<Room> rooms)
{
this.USE.days = days;
this.USE.periods = periods;
this.USE.rooms = rooms;
this.USE.schedualArray = new Period[days, periods];
this.USE.subjectCount = 0;
for (int i = 0; i < days; i++)
{
for (int j = 0; j < periods; j++)
{
USE.schedualArray[i, j] = new Period(CloneList(ref rooms)); //here i cloned the list to be in the safe side and it didn't work also
}
}
}
private Structure(datenStruct struc)
{
this.USE = struc;
}
internal bool AddSubject(Sub subject, int day, int period)
{
//add the subject into inner lists (room)
return true;
}
public void PrintStruct()
{
for (int i = 0; i < USE.days; i++)
{
for (int j = 0; j < USE.periods; j++)
{
foreach (var subject in USE.schedualArray[i, j].Subjects)
{
Console.Write("\t\t");
}
Console.Write("\t\t");
}
Console.WriteLine();
}
}
public List<Room> CloneList(ref List<Room> rooms)
{
var lst = new List<Room>();
foreach (var room in rooms)
{
lst.Add((Room)room.Clone());
}
return lst;
}
internal void RemoveSubject(Sub subject)
{
//..................
}
#region IDisposable Members
public void Dispose()
{
// GC.Collect(g, GCCollectionMode.Forced);
}
#endregion
public object Clone()
{
var copie =new datenStruct();
copie.days = USE.days;
copie.subjectCount = USE.subjectCount;
copie.periods = USE.periods;
var RoomListCopie = new List<Room>();
foreach (Room origSub in USE.rooms)
RoomListCopie.Add((Room)origSub.Clone());
copie.rooms = RoomListCopie;
copie.schedualArray = new Period[copie.days, copie.periods];
for (int i = 0; i < copie.days; i++)
{
for (int j = 0; j < copie.periods; j++)
{
copie.schedualArray[i, j] = new Period(CloneList(ref copie.rooms));
}
}
return new Structure(copie);
}
}
i wrote this code i think it solve my problem but if you have any other answers please inform me.
private Structure SpecialClone(Structure s)
{
var rooms = Cloner.DeepClone<List<Room>>(s.Rooms);
var perds = Cloner.DeepClone<Period[,]>(s.SchedualArray);
var days = s.Days;
var periods = s.Periods;
return new Structure(days, periods, rooms, perds, s.SubjectCount);
}
and i added an overloading to the Structure Constructure to do this:
public Structure(int days, int periods, List<Room> rooms, Period[,] _periods,int subjectCount)
{
this.days = days;
this.periods = periods;
this.rooms = rooms.DeepClone();
this.subjectCount = subjectCount;
this.schedualArray = _periods.Clone() as Period[,];
}
I'm having an issue trying to convert an Enum to JSON string for jQGrid. The format I was using before (doing a manually conversion) was this:
{{0: '-', 1: 'Active', 2: 'Deactive', 3: 'Pending'}}
public static string GetStatuses(bool addDefault = false)
{
var statusesEnum = Enum.GetValues(typeof(StatusEnum));
string statuses = "{value: {0: '-', ";
foreach (StatusEnum status in statusesEnum)
statuses += String.Format("{0}: '{1}', ", (byte)status, Enum.GetName(typeof(StatusEnum), status));
return statuses.Substring(0, statuses.Length - 2) + "}}";
}
So I need to avoid this method because I think is not the best approach for this, I would like to serialize it using the JSON.NET library. So I wrote this:
public class StatusJSON
{
public byte ID { get; set; }
public string Name { get; set; }
public StatusJSON() { }
public StatusJSON(byte id, string name)
{
ID = id;
Name = name;
}
}
public class JSONUtils
{
/// <summary>
/// Get all the posible statuses of selected <paramref name="type"/> in JSON
/// </summary>
/// <param name="type">Type of the status</param>
/// <param name="addDefault">Check if add a default / NULL status</param>
/// <returns>A string JSON with the statuses</returns>
public static string GetStatuses(Type type, bool addDefault = false)
{
var statusesEnum = Enum.GetValues(type);
List<StatusJSON> statuses = new List<StatusJSON>();
if (addDefault)
statuses.Add(new StatusJSON(0, "-"));
foreach (var statusEnum in statusesEnum)
statuses.Add(new StatusJSON((byte)statusEnum, Enum.GetName(type, statusEnum)));
return JsonConvert.SerializeObject(statuses);
}
}
You can use it as: string statuses = JSONUtils.GetStatuses(typeof(StatusEnum), addDefault);. The problem is than this return a string like:
[{"ID":0,"Name":"-"},{"ID":1,"Name":"Active"},{"ID":2,"Name":"Deactive"},{"ID":3,"Name":"Pending"}]
There's any method in the library to get a string like the one I need? Thanks
What I did finally is re-use my old code. So now I have this:
public class Statutes
{
public byte ID { get; set; }
public string Name { get; set; }
public Statutes() { }
public Statutes(byte id, string name)
{
ID = id;
Name = name;
}
/// <summary>
/// Get all the posible statuses of selected <paramref name="type"/>
/// </summary>
/// <param name="type">Type of the status</param>
/// <param name="addDefault">Check if add a default / NULL status</param>
/// <returns>A list with the statuses</returns>
public static List<Statutes> SelectAll(Type type, bool addDefault = false)
{
var statusesEnum = Enum.GetValues(type);
List<Statutes> statuses = new List<Statutes>();
if (addDefault)
statuses.Add(new Statutes(0, "-"));
foreach (var statusEnum in statusesEnum)
statuses.Add(new Statutes((byte)statusEnum, Enum.GetName(type, statusEnum)));
return statuses;
}
}
public class JSONUtils
{
/// <summary>
/// Get all the posible statuses of selected <paramref name="type"/> in JSON
/// </summary>
/// <param name="type">Type of the status</param>
/// <param name="addDefault">Check if add a default / NULL status</param>
/// <returns>A string JSON for jQGrid with the statuses</returns>
public static string GetStatusesJQGrid(Type type, bool addDefault = false)
{
var statuses = Statutes.SelectAll(type, addDefault);
string result = "{value: {";
foreach (Statutes status in statuses)
result += String.Format("{0}: '{1}', ", status.ID, status.Name);
return result.Substring(0, result.Length - 2) + "}}";
}
}
You can use it as: string statuses = JSONUtils.GetStatusesJQGrid(typeof(StatusEnum), true);
Until I'll find a better approach using the JSON.NET I think this is a good piece of code to re-use for the people using jQGrid. This is valid for the select option:
colModel: {name: 'status_id', label: 'Status', edittype: 'select', sortable: true, search: true, stype:'select', editoptions: " + statuses + #", searchoptions: {sopt: ['eq', 'ne']}}