I'm working on a program where I have to find the shortest path between 12 cities, starting in Seattle and ending in Miami. I'm using Dijkstra's Algorithm because the paths are weighted. Here is my code so far, it all works except the answer I get is not the one I need, although it is correct.
This part of the code sets everything up as well as creates the sorting algorithm.
class Graph
{
Dictionary<string, Dictionary<string, int>> vertices = new Dictionary<string, Dictionary<string, int>>();
public void add_vertex(string name, Dictionary<string, int> edges)
{
vertices[name] = edges;
}
public List<string> shortest_path(string start, string finish)
{
var previous = new Dictionary<string, string>();
var distances = new Dictionary<string, int>();
var nodes = new List<string>();
List<string> path = null;
foreach (var vertex in vertices)
{
if (vertex.Key == start)
{
distances[vertex.Key] = 1;
}
else
{
distances[vertex.Key] = int.MaxValue;
}
nodes.Add(vertex.Key);
}
while (nodes.Count != 0)
{
nodes.Sort((x, y) => distances[x] - distances[y]);
var smallest = nodes[0];
nodes.Remove(smallest);
if (smallest == finish)
{
path = new List<string>();
while (previous.ContainsKey(smallest))
{
path.Add(smallest);
smallest = previous[smallest];
}
break;
}
if (distances[smallest] == int.MaxValue)
{
break;
}
foreach (var neighbor in vertices[smallest])
{
var alt = distances[smallest] + neighbor.Value;
if (alt < distances[neighbor.Key])
{
distances[neighbor.Key] = alt;
previous[neighbor.Key] = smallest;
}
}
}
return path;
}
}
Below is where I create the "cities" along with creating the values between them.
class MainClass
{
public static void Main(string[] args)
{
Graph g = new Graph();
g.add_vertex("Seattle", new Dictionary<string, int>() { {"San Francisco", 1306}, {"Denver", 2161}, {"Minneapolis", 2661} });
g.add_vertex("San Francisco", new Dictionary<string, int>() { {"Seattle", 1306}, {"Las Vegas", 919}, {"Los Angeles", 629} });
g.add_vertex("Las Vegas", new Dictionary<string, int>() { {"San Francisco", 919}, {"Los Angeles", 435}, {"Denver", 1225}, {"Dallas", 1983} });
g.add_vertex("Los Angeles", new Dictionary<string, int>() { {"San Francisco", 629}, {"Las Vegas", 435} });
g.add_vertex("Denver", new Dictionary<string, int>() { {"Seattle", 2161}, {"Las Vegas", 1225}, {"Minneapolis", 1483}, {"Dallas", 1258} });
g.add_vertex("Minneapolis", new Dictionary<string, int>() { {"Seattle", 2661}, {"Denver", 1483}, {"Dallas", 1532}, {"Chicago", 661} });
g.add_vertex("Dallas", new Dictionary<string, int>() { {"Las Vegas", 1983}, {"Denver", 1258}, {"Minneapolis", 1532}, {"Washington DC", 2113} });
g.add_vertex("Chicago", new Dictionary<string, int>() { {"Minneapolis", 661}, {"Washington DC", 1145}, {"Boston", 1613} });
g.add_vertex("Washington DC", new Dictionary<string, int>() { {"Dallas", 2113}, {"Chicago", 1145}, {"Boston", 725}, {"New York", 383}, {"Miami", 1709} });
g.add_vertex("Boston", new Dictionary<string, int>() { {"Chicago", 1613}, {"Washington DC", 725}, {"New York", 338} });
g.add_vertex("New York", new Dictionary<string, int>() { {"Washington DC", 383}, {"Boston", 338}, {"Miami", 2145} });
g.add_vertex("Miami", new Dictionary<string, int>() { {"Dallas", 2161}, {"Washington DC", 1709}, {"New York", 2145} });
g.shortest_path("Miami", "Seattle").ForEach(x => Console.Write(x + " > "));
}
}
The part that I need help figuring out is when I run the program, I get: Seattle > Denver > Dallas. That answer is correct for the shortest distance to Miami, but I need the shortest distance to every city, not just Miami. I just don't know what I need to change to display that properly.
To my understanding, the provided code implements Dijkstra's Algorithm, modified to terminate as soon as some desired destination node is selected into the set of nodes for which the shortest path from the initial node is known. Dijkstra's algorithm solves the so-called Single Source Shortest Path problem. This means that some initial node, in this case Miami, is specified, and the desired result is consituted by the shortest paths to all other nodes. It does not solve the All-Pairs Shortest Path problem, which requires calculation of the respective distance for each pair nodes. This problem can be solved by the Floyd-Warshall Algorithm, however.
In contrast, if you need the shortest path from Miami to all other cities, modifiy the implementation not to break the loop early and remove the second argument.
The line
g.shortest_path("Miami", "Seattle").ForEach(x => Console.Write(x + " > "));
is where you both specify the endpoint of "Miami" and write the output to the console.
You need to create a loop around that line that specifies every endpoint you want
foreach(var endpoint in validEndpoints) {
g.shortest_path(endpoint, "Seattle").ForEach(x => Console.Write(x + " > "));
}
This will be slow and there are things you can do such as memoization to speed it up, but should at least produce the output you want.
I been posting this code for years. You need a recursive algorithm.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
//this one uses strings as node names
Dijkstra1.Program.Dijkstra();
//this one uses integers as node names
Dijkstra2.Program.Dijkstra();
}
}
}
namespace Dijkstra1
{
class Program
{
//A connected to B
//B connected to A, C , D
//C connected to B, D
//D connected to B, C , E
//E connected to D.
static List<List<String>> input1 = new List<List<string>>{
new List<String>() {"A","0","1","0","0","0"},
new List<String>() {"B","1","0","1","1","0"},
new List<String>() {"C","0","1","0","1","0"},
new List<String>() {"D","0","1","1","0","1"},
new List<String>() {"E","0","0","0","1","0"}
};
//A | 0 1 2 2 3 |
//B | 1 0 1 1 2 |
//C | 2 1 0 1 2 |
//D | 2 1 1 0 1 |
//E | 3 2 2 1 0 |
static List<List<String>> input2 = new List<List<string>>{
new List<String>() {"A","0","1","2","2","3"},
new List<String>() {"B","1","0","1","1","2"},
new List<String>() {"C","2","1","0","1","2"},
new List<String>() {"D","2","1","1","0","1"},
new List<String>() {"E","3","2","2","1","0"}
};
static public void Dijkstra()
{
CGraph cGraph;
cGraph = new CGraph(input1);
Console.WriteLine("-------------Input 1 -------------");
cGraph.PrintGraph();
cGraph = new CGraph(input2);
Console.WriteLine("-------------Input 2 -------------");
cGraph.PrintGraph();
}
class CGraph
{
List<Node> graph = new List<Node>();
public CGraph(List<List<String>> input)
{
foreach (List<string> inputRow in input)
{
Node newNode = new Node();
newNode.name = inputRow[0];
newNode.distanceDict = new Dictionary<string, Path>();
newNode.visited = false;
newNode.neighbors = new List<Neighbor>();
//for (int index = 1; index < inputRow.Count; index++)
//{
// //skip diagnol values so you don't count a nodes distance to itself.
// //node count start at zero
// // index you have to skip the node name
// //so you have to subtract one from the index
// if ((index - 1) != nodeCount)
// {
// string nodeName = input[index - 1][0];
// int distance = int.Parse(inputRow[index]);
// newNode.distanceDict.Add(nodeName, new List<string>() { nodeName });
// }
//}
graph.Add(newNode);
}
//initialize neighbors using predefined dictionary
for (int nodeCount = 0; nodeCount < graph.Count; nodeCount++)
{
for (int neighborCount = 0; neighborCount < graph.Count; neighborCount++)
{
//add one to neighbor count to skip Node name in index one
if (input[nodeCount][neighborCount + 1] != "0")
{
Neighbor newNeightbor = new Neighbor();
newNeightbor.node = graph[neighborCount];
newNeightbor.distance = int.Parse(input[nodeCount][neighborCount + 1]);
graph[nodeCount].neighbors.Add(newNeightbor);
Path path = new Path();
path.nodeNames = new List<string>() { input[neighborCount][0] };
//add one to neighbor count to skip Node name in index one
path.totalDistance = int.Parse(input[nodeCount][neighborCount + 1]);
graph[nodeCount].distanceDict.Add(input[neighborCount][0], path);
}
}
}
foreach (Node node in graph)
{
foreach (Node nodex in graph)
{
node.visited = false;
}
TransverNode(node);
}
}
public class Neighbor
{
public Node node { get; set; }
public int distance { get; set; }
}
public class Path
{
public List<string> nodeNames { get; set; }
public int totalDistance { get; set; }
}
public class Node
{
public string name { get; set; }
public Dictionary<string, Path> distanceDict { get; set; }
public Boolean visited { get; set; }
public List<Neighbor> neighbors { get; set; }
}
static void TransverNode(Node node)
{
if (!node.visited)
{
node.visited = true;
foreach (Neighbor neighbor in node.neighbors)
{
TransverNode(neighbor.node);
string neighborName = neighbor.node.name;
int neighborDistance = neighbor.distance;
//compair neighbors dictionary with current dictionary
//update current dictionary as required
foreach (string key in neighbor.node.distanceDict.Keys)
{
if (key != node.name)
{
int neighborKeyDistance = neighbor.node.distanceDict[key].totalDistance;
if (node.distanceDict.ContainsKey(key))
{
int currentDistance = node.distanceDict[key].totalDistance;
if (neighborKeyDistance + neighborDistance < currentDistance)
{
List<string> nodeList = new List<string>();
nodeList.AddRange(neighbor.node.distanceDict[key].nodeNames);
nodeList.Insert(0, neighbor.node.name);
node.distanceDict[key].nodeNames = nodeList;
node.distanceDict[key].totalDistance = neighborKeyDistance + neighborDistance;
}
}
else
{
List<string> nodeList = new List<string>();
nodeList.AddRange(neighbor.node.distanceDict[key].nodeNames);
nodeList.Insert(0, neighbor.node.name);
Path path = new Path();
path.nodeNames = nodeList;
path.totalDistance = neighbor.distance + neighborKeyDistance;
node.distanceDict.Add(key, path);
}
}
}
}
}
}
public void PrintGraph()
{
foreach (Node node in graph)
{
Console.WriteLine("Node : {0}", node.name);
foreach (string key in node.distanceDict.Keys.OrderBy(x => x))
{
Console.WriteLine(" Distance to node {0} = {1}, Path : {2}", key, node.distanceDict[key].totalDistance, string.Join(",", node.distanceDict[key].nodeNames.ToArray()));
}
}
}
}
}
}
namespace Dijkstra2
{
class Program
{
//0---1---2---3
// |
// 4
// |
// 5---6---7
// \ /
// 8
// |
// 9
static List<List<int>> input1 = new List<List<int>>
{ // 0 1 2 3 4 5 6 7 8 9
new List<int>() {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0},
new List<int>() {1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0},
new List<int>() {2, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0},
new List<int>() {3, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0},
new List<int>() {4, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0},
new List<int>() {5, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0},
new List<int>() {6, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0},
new List<int>() {7, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0},
new List<int>() {8, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1},
new List<int>() {9, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0},
};
static public void Dijkstra()
{
CGraph cGraph;
cGraph = new CGraph(input1);
Console.WriteLine("-------------Input 1 -------------");
cGraph.PrintGraph();
}
class CGraph
{
List<Node> graph = new List<Node>();
public CGraph(List<List<int>> input)
{
foreach (List<int> inputRow in input)
{
Node newNode = new Node();
newNode.name = inputRow[0];
newNode.distanceDict = new Dictionary<int, Path>();
newNode.visited = false;
newNode.neighbors = new List<Neighbor>();
//for (int index = 1; index < inputRow.Count; index++)
//{
// //skip diagnol values so you don't count a nodes distance to itself.
// //node count start at zero
// // index you have to skip the node name
// //so you have to subtract one from the index
// if ((index - 1) != nodeCount)
// {
// string nodeName = input[index - 1][0];
// int distance = int.Parse(inputRow[index]);
// newNode.distanceDict.Add(nodeName, new List<string>() { nodeName });
// }
//}
graph.Add(newNode);
}
//initialize neighbors using predefined dictionary
for (int nodeCount = 0; nodeCount < graph.Count; nodeCount++)
{
for (int neighborCount = 0; neighborCount < graph.Count; neighborCount++)
{
//add one to neighbor count to skip Node name in index one
if (input[nodeCount][neighborCount + 1] != 0)
{
Neighbor newNeightbor = new Neighbor();
newNeightbor.node = graph[neighborCount];
newNeightbor.distance = input[nodeCount][neighborCount + 1];
graph[nodeCount].neighbors.Add(newNeightbor);
Path path = new Path();
path.nodeNames = new List<int>() { input[neighborCount][0] };
//add one to neighbor count to skip Node name in index one
path.totalDistance = input[nodeCount][neighborCount + 1];
graph[nodeCount].distanceDict.Add(input[neighborCount][0], path);
}
}
}
foreach (Node node in graph)
{
foreach (Node nodex in graph)
{
node.visited = false;
}
TransverNode(node);
}
}
public class Neighbor
{
public Node node { get; set; }
public int distance { get; set; }
}
public class Path
{
public List<int> nodeNames { get; set; }
public int totalDistance { get; set; }
}
public class Node
{
public int name { get; set; }
public Dictionary<int, Path> distanceDict { get; set; }
public Boolean visited { get; set; }
public List<Neighbor> neighbors { get; set; }
}
static void TransverNode(Node node)
{
if (!node.visited)
{
node.visited = true;
foreach (Neighbor neighbor in node.neighbors)
{
TransverNode(neighbor.node);
int neighborName = neighbor.node.name;
int neighborDistance = neighbor.distance;
//compair neighbors dictionary with current dictionary
//update current dictionary as required
foreach (int key in neighbor.node.distanceDict.Keys)
{
if (key != node.name)
{
int neighborKeyDistance = neighbor.node.distanceDict[key].totalDistance;
if (node.distanceDict.ContainsKey(key))
{
int currentDistance = node.distanceDict[key].totalDistance;
if (neighborKeyDistance + neighborDistance < currentDistance)
{
List<int> nodeList = new List<int>();
nodeList.AddRange(neighbor.node.distanceDict[key].nodeNames);
nodeList.Insert(0, neighbor.node.name);
node.distanceDict[key].nodeNames = nodeList;
node.distanceDict[key].totalDistance = neighborKeyDistance + neighborDistance;
}
}
else
{
List<int> nodeList = new List<int>();
nodeList.AddRange(neighbor.node.distanceDict[key].nodeNames);
nodeList.Insert(0, neighbor.node.name);
Path path = new Path();
path.nodeNames = nodeList;
path.totalDistance = neighbor.distance + neighborKeyDistance;
node.distanceDict.Add(key, path);
}
}
}
}
}
}
public void PrintGraph()
{
foreach (Node node in graph)
{
Console.WriteLine("Node : {0}", node.name);
foreach (int key in node.distanceDict.Keys.OrderBy(x => x))
{
Console.WriteLine(" Distance to node {0} = {1}, Path : {2}", key, node.distanceDict[key].totalDistance, string.Join(",", node.distanceDict[key].nodeNames.ToArray()));
}
}
}
}
}
}
Related
I have two list of two dimensional array
List<double[,]>list1=new List<double[4,4]>();
List<double[,]>list2=new List<double[4,4]>();
The length of lists are not necessarily equal.
What you have does not work because Contains will do a reference comparison to check equality when iterating the list. Unless your 2d arrays in each list refer to the same object reference, even if they're semantically the same it would not identify them as being equal.
For example, in this case the match would be found:
var my2d = new double[2, 2] { { 1, 3 }, { 3, 5 } };
List<double[,]> list1 = new List<double[,]>() { my2d };
List<double[,]> list2 = new List<double[,]>() { my2d };
foreach (var matrix in list1)
if (list2.Contains(matrix))
Console.WriteLine("FOUND!");
But if we change the lists to have separate instances of the 2d array, it would not:
List<double[,]> list1 = new List<double[,]>() { new double[2, 2] { { 1, 3 }, { 3, 5 } } };
List<double[,]> list2 = new List<double[,]>() { new double[2, 2] { { 1, 3 }, { 3, 5 } } };
One way you could overcome this is to specify your own IEqualityComparer to tell the Contains method how to perform a comparison. For example, here is something that could compare a two dimension array element by element:
public class TwoDimensionCompare<T> : IEqualityComparer<T[,]>
{
public bool Equals(T[,] x, T[,] y)
{
// fail fast if the sizes aren't the same
if (y.GetLength(0) != x.GetLength(0)) return false;
if (y.GetLength(1) != x.GetLength(1)) return false;
// compare element by element
for (int i = 0; i < y.GetLength(0); i++)
for (int z = 0; z < y.GetLength(1); z++)
if (!EqualityComparer<T>.Default.Equals(x[i, z], y[i, z])) return false;
return true;
}
public int GetHashCode(T[,] obj)
{
return obj.GetHashCode();
}
}
Usage:
List<double[,]> list1 = new List<double[,]>() { new double[2, 2] { { 1, 3 }, { 3, 5 } } };
List<double[,]> list2 = new List<double[,]>() { new double[2, 2] { { 1, 3 }, { 3, 5 } } };
foreach (var matrix in list1)
if (list2.Contains(matrix, new TwoDimensionCompare<double>()))
Console.WriteLine("FOUND!");
I am trying to fill a tree with more than one parameter (points and types) and at the end, show which "branch" has the max of points and in every branch, show how many equal tupe I have.
The tree will be something like this:
FATHER (Points:200|Type:2)
|_CHILD01 (P:120|Type:3)
| |_CHILD4 (P:300|T:3)
| | |_CHILD8 (P:220|T:3)
| | |_CHILD9 (P:65|T:1)
| |_CHILD5 (P:15|T:9)
|_CHILD2 (P:10|T:1)
|_CHILD3 (P:80|T:2)
|_CHILD6 (P:25|T:2)
| |_CHILD10 (P:110|T:7)
| |_CHILD11 (P:195|T:3)
|_CHILD7 (P:50|T:7)
and what I am trying to get is:
NUMBER OF POINTS PER BRANCH:
Branch01 -> FATHER (200), CHILD01 (120), CHILD04 (300), CHILD08 (220) -> TotalPoints: 840
Branch02 -> FATHER (200), CHILD01 (120), CHILD04 (300), CHILD09 (65) -> TotalPoints: 685
Branch03 -> FATHER (200), CHILD01 (120), CHILD05 (15) -> TotalPoints: 335
Branch04 -> FATHER (200), CHILD02 (10) -> TotalPoints: 210
Branch05 -> FATHER (200), CHILD03 (80), CHILD06 (25), CHILD10 (110) -> TotalPoints: 415
Branch06 -> FATHER (200), CHILD03 (80), CHILD06 (25), CHILD11 (195) -> TotalPoints: 500
Branch07 -> FATHER (200), CHILD03 (80), CHILD07 (50) -> TotalPoints: 330
and
COUNT THE NUMBER OF TYPES in WHICH BRANCH:
TypePerBranch01:
- Type1:0
- Type2:1
- Type3:2
- Type4:1
- Type5:0
- Type6:0
- Type7:0
- Type8:0
- Type9:0
TypePerBranch02:
- Type1:1
- Type2:1
- Type3:1
- Type4:1
- Type5:0
- Type6:0
- Type7:0
- Type8:0
- Type9:0
TypePerBranch03:
- Type1:0
- Type2:1
- Type3:1
- Type4:0
- Type5:0
- Type6:0
- Type7:0
- Type8:0
- Type9:1
TypePerBranch04:
- Type1:1
- Type2:1
- Type3:0
- Type4:0
- Type5:0
- Type6:0
- Type7:0
- Type8:0
- Type9:0
TypePerBranch05:
- Type1:0
- Type2:3
- Type3:0
- Type4:0
- Type5:0
- Type6:0
- Type7:1
- Type8:0
- Type9:0
TypePerBranch06:
- Type1:0
- Type2:3
- Type3:1
- Type4:0
- Type5:0
- Type6:0
- Type7:0
- Type8:0
- Type9:0
TypePerBranch07:
- Type1:0
- Type2:2
- Type3:0
- Type4:0
- Type5:0
- Type6:0
- Type7:1
- Type8:0
- Type9:0
I have done some code but its not working.
Here´s the function:
//
// FUNÇÃO ResizeArray
public T[,] ResizeArray<T>(T[,] original, int xSize, int ySize)
{
var newArray = new T[xSize, ySize];
var xMin = Math.Min(xSize, original.GetLength(0));
var yMin = Math.Min(ySize, original.GetLength(1));
for (var x = 0; x < xMin; x++)
for (var y = 0; y < yMin; y++)
newArray[x, y] = original[x, y];
return newArray;
}
//
// FUNÇÃO TreeBranchPath
int[] TotalPontosRamo = new int[1];
int[,] FolhaInfoPontos = new int[1, 1];
int[,] FolhaInfoPatamar = new int[1, 1];
int CountRamos = 0;
private void TreeBranchPath(int idusr, int usrpnts, int usrpata, int nivelnum, int ramonum)
{
FolhaInfoPontos[nivelnum, ramonum] = usrpnts;
FolhaInfoPatamar[nivelnum, ramonum] = usrpata;
var AfilhadosList = (from af in db.NRV_USERS
where af.idpatrocinador == idusr
select af).ToList();
/*Se for NULL não tem descendentes */
if (AfilhadosList != null)
{
int CountNumFilhos = AfilhadosList.Count();
int CountFilhos = 0;
nivelnum = nivelnum + 1;
FolhaInfoPontos = ResizeArray(FolhaInfoPontos, nivelnum, ramonum + CountNumFilhos);
FolhaInfoPatamar = ResizeArray(FolhaInfoPatamar, nivelnum, ramonum + CountNumFilhos);
foreach (var descid in AfilhadosList)
{
CountFilhos = CountFilhos + 1;
/* Inicio - Quantos Pontos o User tem */
var UserPoints = (from pnt in db.NRV_USERPONTOS
where pnt.iduser == descid.id_user && pnt.usrpntact == true
select pnt).FirstOrDefault();
int TotalUserPoints = UserPoints.pontosgrupo + UserPoints.pontosproprios;
/* Fim - Quantos Pontos o User tem */
TotalPontosRamo[CountRamos] = TotalPontosRamo[CountRamos] + TotalUserPoints;
/* Inicio - Em que Patamar o User está */
var AuxUserPatamar = (from cp in db.NRV_USERPATAMAR
where cp.iduser == idusr
select cp.idpatamax).FirstOrDefault();
/* Fim - Em que Patamar o User está */
Array.Resize(ref TotalPontosRamo, CountRamos + 1);
TreeBranchPath(descid.id_user, TotalUserPoints, AuxUserPatamar, nivelnum, CountFilhos);
}
}
else
{
return;
}
}
Can someone help me?
Here I indented the results based on the level of the Node.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
Node father = new Node()
{
name = "FATHER", points = 200, type = 2, children = new List<Node>(){
new Node() {
name = "CHILD01", points = 120, type = 3, children = new List<Node>(){
new Node(){
name = "CHILD04", points = 300, type = 3, children = new List<Node>(){
new Node(){ name = "CHILD08", points = 220, type = 3, children = null},
new Node(){ name = "CHILD09", points = 65, type = 1, children = null}
}
},
new Node(){ name = "CHILD05", points = 15, type = 9, children = null}
}
},
new Node() { name = "CHILD02", points = 10, type = 1, children = null},
new Node(){
name = "CHILD03", points = 80, type = 2, children = new List<Node>(){
new Node(){
name = "CHILD06", points = 25, type = 2, children = new List<Node>(){
new Node(){ name = "CHILD10", points = 110, type = 7, children = null},
new Node(){ name = "CHILD11", points = 195, type = 3, children = null}
}
},
new Node(){ name = "CHILD07", points = 50, type = 7, children = null}
}
}
}
};
Count results = father.GetTotals(0);
foreach (Count result in Node.results)
{
Console.WriteLine("{0} Name = {1}, Points = {2}, Types = {3}",
string.Join("", Enumerable.Repeat(" ", result.level)),
result.name,
result.points,
string.Join(",", result.types.OrderBy(x => x.Key).Select(x => x.Key.ToString() + ":" + x.Value.ToString()).ToArray())
);
}
}
}
public class Count
{
public string name;
public int level { get; set; }
public int points { get; set; }
public Dictionary<int, int> types { get; set; }
}
public class Node
{
public string name { get; set; }
public int points { get; set; }
public int type { get; set; }
public List<Node> children { get; set; }
public static List<Count> results = new List<Count>();
public Count GetTotals(int level)
{
Count result = new Count();
result.name = name;
result.level = level;
result.points = points;
result.types = new Dictionary<int, int>();
result.types.Add(type, 1);
if (children != null)
{
for (int childCount = children.Count - 1; childCount >= 0; childCount--)
{
Node child = children[childCount];
Count childResutls = child.GetTotals(level + 1);
result.points += childResutls.points;
foreach (int key in childResutls.types.Keys)
{
if (result.types.ContainsKey(key))
{
result.types[key] += childResutls.types[key];
}
else
{
result.types.Add(key, childResutls.types[key]);
}
}
}
}
Node.results.Insert(0, result);
return result;
}
}
}
Here is a slightly different answer with the nodes in the same order as the input
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
Node father = new Node()
{
name = "FATHER", points = 200, type = 2, children = new List<Node>(){
new Node() {
name = "CHILD01", points = 120, type = 3, children = new List<Node>(){
new Node(){
name = "CHILD04", points = 300, type = 3, children = new List<Node>(){
new Node(){ name = "CHILD08", points = 220, type = 3, children = null},
new Node(){ name = "CHILD09", points = 65, type = 1, children = null}
}
},
new Node(){ name = "CHILD05", points = 15, type = 9, children = null}
}
},
new Node() { name = "CHILD02", points = 10, type = 1, children = null},
new Node(){
name = "CHILD03", points = 80, type = 2, children = new List<Node>(){
new Node(){
name = "CHILD06", points = 25, type = 2, children = new List<Node>(){
new Node(){ name = "CHILD10", points = 110, type = 7, children = null},
new Node(){ name = "CHILD11", points = 195, type = 3, children = null}
}
},
new Node(){ name = "CHILD07", points = 50, type = 7, children = null}
}
}
}
};
Count results = father.GetTotals();
foreach (Count result in Node.results)
{
Console.WriteLine("Name = {0}, Points = {1}, Types = {2}",
result.name,
result.points,
string.Join(",", result.types.OrderBy(x => x.Key).Select(x => x.Key.ToString() + ":" + x.Value.ToString()).ToArray())
);
}
}
}
public class Count
{
public string name;
public int points { get; set; }
public Dictionary<int, int> types { get; set; }
}
public class Node
{
public string name { get; set; }
public int points { get; set; }
public int type { get; set; }
public List<Node> children { get; set; }
public static List<Count> results = new List<Count>();
public Count GetTotals()
{
Count result = new Count();
result.name = name;
result.points = points;
result.types = new Dictionary<int, int>();
result.types.Add(type, 1);
if (children != null)
{
for (int childCount = children.Count - 1; childCount >= 0; childCount--)
{
Node child = children[childCount];
Count childResutls = child.GetTotals();
result.points += childResutls.points;
foreach (int key in childResutls.types.Keys)
{
if (result.types.ContainsKey(key))
{
result.types[key] += childResutls.types[key];
}
else
{
result.types.Add(key, childResutls.types[key]);
}
}
}
}
Node.results.Insert(0, result);
return result;
}
}
}
I have a List of items containing either 1 or 0, I'm looking to output the items only where there are six 1's back to back in the list. So only write to the console if the item in this list is part of a group of six.
1
1
1
1
1
1
0
1
1
1
0
In the above list, the first six items would be output but the bottom set of three 1s would not as they are not part of a group of six.
Is this a job for LINQ or RegEx?
You can concatenate all values into string, then split it by zeros. From substrings select those which have at least 6 characters:
List<int> values = new List<int> { 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0 };
var series = String.Concat(values)
.Split(new[] { '0' }, StringSplitOptions.RemoveEmptyEntries)
.Where(s => s.Length >= 6);
For given input data series will contain single item "111111" which you can output to console.
Classic run length encoding, O(n), lazy evaluated, stack agnostic, generic for any equatable type.
public void TestRunLength()
{
var runs = new List<int>{ 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 2, 2, 3, 4, 4, 0, 4};
var finalGroup = RunLength(runs).FirstOrDefault(i => i.Count == 6 && i.First() == 1);
}
private IEnumerable<List<T>> RunLength<T>(IEnumerable<T> source) where T : IEquatable<T>
{
T current = default(T);
var requiresInit = true;
var list = new List<T>();
foreach (var i in source)
{
if (requiresInit)
{
current = i;
requiresInit = false;
}
if (i.Equals(current))
{
list.Add(i);
}
else
{
yield return list;
list = new List<T>{ i };
current = i;
}
}
if (list.Any())
{
yield return list;
}
}
And because it's lazy it works on infinite sequences (yes I know its not infinite, but it is large)!
public void TestRunLength()
{
var random = new Random();
var runs = Enumerable.Range(int.MinValue, int.MaxValue)
.Select(i => random.Next(0, 10));
var finalGroup = RunLength(runs)
.FirstOrDefault(i => i.Count == 6);
}
Probably it can be done with Regex too if you concatenate your numbers into a string. But I would prefer linq:
var bits = new List<int> {1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0};
int bitCountPerGroup = 6;
var result = bits // (1) (2)
.Select((x,idx) => bits.Skip(idx).TakeWhile(y => y == x))
.Where(g => g.Count() == bitCountPerGroup); // (3)
foreach (var set in result)
Console.WriteLine(string.Join(" ", set));
This code gets a number-set for each number by starting from the number (1) and taking the next numbers as long as they are equal (2). Then filter the groups and gets only those groups which have 6 numbers (3).
If for example your list is of an unknown size,or better,you do not know the items in it you could do this recursive example(note that i placed more zeros so it would fetch 2 sets of data,it works with yours also),and pass to the method the amout to group by:
//this is the datastructure to hold the results
static List<KeyValuePair<string, List<int>>> Set = new List<KeyValuePair<string, List<int>>>();
private static void GetData(List<int> lst, int group)
{
int count = 1;
int pivot = lst.First();
if (lst.Count < group)
{
return;
}
else
{
foreach (int i in lst.Skip(1))
{
if (i == pivot)
{
count++;
}
else if (count == group)
{
Set.Add(new KeyValuePair<string, List<int>>("Set of items " + pivot, lst.Take(count).ToList()));
GetData(lst.Skip(count).ToList(), group);
break;
}
else
{
GetData(lst.Skip(count).ToList(), group);
break;
}
}
}
}
Then in Main():
static void Main(string[] args)
{
List<int> test = new List<int> { 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0 };
GetData(test, 6);
foreach (var item in Set)
{
Console.WriteLine("\t" + item.Key);
foreach (var subitem in item.Value)
{
Console.WriteLine(subitem);
}
}
}
I want to try to select routes from known points as seen below. But I cannot achieve to get appropriate route chain for example for point 2 to 8. According to this trial route1-route2 and route3 will be selected, but actually must be only route1 and route3, another example point 1 to point 11, my trial will give result all routes. How can I eliminate unnecessary routes.Is this possible with this trial or should I change my point of view?
static void Main(string[] args)
{
var route1 = new List<int> { 1, 2, 3, 4 };
var route2 = new List<int> { 1, 5, 6, 7 };
var route3 = new List<int> { 1, 8, 9, 10 };
var route4 = new List<int> { 10, 11, 12, 13 };
List<List<int>> routeList = new List<List<int>>();
routeList.Add(route1);
routeList.Add(route2);
routeList.Add(route3);
routeList.Add(route4);
int start = 3;
int end = 9;
var vistedRoutes = new List<List<int>>();
foreach(var route in routeList.FindAll(r => r.Contains(start)))
{
vistedRoutes.Add(route);
routeList.Remove(route);
FindPath(vistedRoutes, routeList, start, end);
if (vistedRoutes.Last().Contains(end))
{
break;
}
}
Console.WriteLine("done");
}
static void FindPath(List<List<int>> visitedRoutes, List<List<int>> remainingRoutes, int start, int end)
{
if (visitedRoutes.Last().Contains(end))
{
return;
}
for (int i = 0; i < remainingRoutes.Count; i++ )
{
var route = remainingRoutes[i];
foreach (var point in route)
{
if (visitedRoutes.Last().Contains(point))
{
visitedRoutes.Add(route);
var newRemainingRoutes = new List<List<int>>(remainingRoutes);
newRemainingRoutes.Remove(route);
FindPath(visitedRoutes, newRemainingRoutes, start, end);
if (visitedRoutes.Last().Contains(end))
{
return;
}
else
{
visitedRoutes.Remove(route);
}
}
}
}
}
I have just recently been doing something in C#, i would like to know how to do something like this.
Array[0] =
Array['Value'] = 2344;
Array['LocationX'] = 0;
Array['LocationY'] = 0;
Array[1] =
Array['Value'] = 2312;
Array['LocationX'] = 2;
Array['LocationY'] = 1;
Array[2] =
Array['Value'] = 2334;
Array['LocationX'] = 4;
Array['LocationY'] = 3;
The data it self its not important, the thing is that i know how to do this in PHP. But in C# i don't, and I've tried some ways and no luck.
In PHP i could just do something like this:
$Array[0]->Value = 2344;
$Array[0]->LocationX = 0;
$Array[0]->LocationY = 0;
And those values would be added to the Array.
In C# i've tried this and doesn't work that way.
Could someone enlighten me in how to do this in C#?
Thanks.
Well, you could have an array of instances of a class that you write like so:
public class DataForArray
{
public int Value { get; set; }
public int LocationX { get; set; }
public int LocationY { get; set; }
}
Then something like this:
DataForArray[] array = new DataForArray[10];
array[0] = new DataForArray();
array[0].Value = 2344;
etc...
Either write a class or struct to hold Value, LocationX and LocationY.
struct Foo
{
Foo(value, x, y)
{
Value = value;
LocationX = x;
LocationY = y;
}
Foo() {}
int Value;
int LocationX;
int LocationY;
}
Foo[] f = new []
{
new Foo(1, 2, 3),
new Foo(2, 3, 4)
}
or alternatively initialize the array this way:
Foo[] f = new []
{
new Foo() { Value = 1, LocationX = 2, LocationY = 3 },
new Foo() { Value = 4, LocationX = 5, LocationY = 6 },
}
Or use an Array of Dictionary<string, int>.
Dictionary<string, int>[] array = new []
{
new Dictionary<string, int>() {{ "Value", 1 }, {"LocationX", 2}, {"LocationY", 3 }},
new Dictionary<string, int>() {{ "Value", 4 }, {"LocationX", 5}, {"LocationY", 6 }}
}
Which is only recommended if it needs to be dynamic (means: you want to have different values in each element of the array or your keys are in strings, not known at compile-time.) Unless it is just hard to maintain.
in C#, you can try something like this
// initialize array
var list = new[]
{
new {Value = 2344, LocationX = 0, LocationY = 0},
new {Value = 2312, LocationX = 2, LocationY = 4},
new {Value = 2323, LocationX = 3, LocationY = 1}
}.ToList();
// iterate over array
foreach (var node in list)
{
var theValue = node.Value;
var thePosition = new Point(node.LocationX, node.LocationY);
}
// iterate over array with filtering ( value > 2300 )
foreach (var node in list.Where(el => el.Value > 2300))
{
var theValue = node.Value;
var thePosition = new Point(node.LocationX, node.LocationY);
}
// add again
list.Add(new { Value = 2399, LocationX = 9, LocationY = 9 });
Here is a link that details the use of Multidimensional arrays
http://msdn.microsoft.com/en-us/library/aa288453(VS.71).aspx
You can use anonymous type in C# like that:
var arr = new[] {
new{Value = 1, LocationX = 2, LocationY = 3},
new{Value = 1, LocationX = 2, LocationY = 3},
new{Value = 1, LocationX = 2, LocationY = 3},
new{Value = 1, LocationX = 2, LocationY = 3},
new{Value = 1, LocationX = 2, LocationY = 3} };
Only one problem is that properties in anonymous type are read-only. So You can't do something like that:
arr[1].Value = 2