C# dynamic tree with many parameters, how to do it? - c#

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;
}
}
}
​

Related

how do i calculate Qty To Be Issued in List collection

List<Serials> serials = new List<Serials>
{
new Serials { Id = 1, Qty = 30, SRNo = "SR-001" },
new Serials { Id = 2, Qty = 70, SRNo = "SR-002" }
};
decimal? QtyToBeIssued = 50;
// i tried however i did not get it in foreach loop
foreach (var item in serials)
{
decimal? ToBeIssued = 0;
if (QtyToBeIssued > item.Qty)
{
ToBeIssued = item.Qty;
item.Qty = item.Qty - ToBeIssued;
}
}
QtyToBeIssued = 50 and serials collection's has first object has 30 i.e need to subtract 30 - 30 = 0 and remaining qty= 20
and that remaining 20 subtract from 2nd collection i.e 70-20 = 50
so my object collection will be looks like below after calculation
.i need to issue 30 from 1st record and 20 from second record.
Id = 1, Qty = 0, SRNo = "SR-001"
Id = 2, Qty = 50, SRNo = "SR-002"
you can use the bellow code
List<Serials> serials = new List<Serials>
{
new Serials { Id = 1, Qty = 30, SRNo = "SR-001" },
new Serials { Id = 2, Qty = 70, SRNo = "SR-002" }
};
int QtyToBeIssued = 50;
foreach (var item in serials)
{
int ToBeIssued = 0;
if (QtyToBeIssued > 0)
{
var temp = item.Qty - QtyToBeIssued < 0 ? 0 : item.Qty - QtyToBeIssued;
QtyToBeIssued -= item.Qty;
item.Qty = temp;
}
}
You can achieve by this way, live demo here
var count = 0;
serials.ForEach(p =>
{
count++;
if (QtyToBeIssued >= p.Qty)
{
QtyToBeIssued -= p.Qty;
p.Qty = 0;
}
if (count == serials.Count)
{
p.Qty -= (int)QtyToBeIssued;
}
});
Out put:
ID: 1 Qty: 0 SRNo: SR-001
ID: 2 Qty: 50 SRNo: SR-002
You are not modifying the QtyToBeIssued in your for loop. To match the description of your code, you have to also cover the case when QtyToBeIssued is not enough for your item.
So I would do something like this:
List<Serials> serials = new List<Serials>
{
new Serials { Id = 1, Qty = 30, SRNo = "SR-001" },
new Serials { Id = 2, Qty = 70, SRNo = "SR-002" }
};
decimal? QtyToBeIssued = 50;
foreach (var item in serials)
{
decimal? ToBeIssued = 0;
if (QtyToBeIssued > item.Qty)
{
ToBeIssued = item.Qty;
}
else // QtyTyBeIssued <= item.Qty
{
ToBeIssued = QtyToBeIssued;
}
item.Qty = item.Qty - ToBeIssued;
QtyToBeIssued = QtyToBeIssued - ToBeIssued;
}
Edit: and for shorter code:
foreach (var item in serials)
{
decimal? ToBeIssued = Math.Min(item.Qty, QtyToBeIssued);
item.Qty -= ToBeIssued;
QtyToBeIssued -= ToBeIssued;
}
You can try this:
List<Serials> serials = new List<Serials>
{
new Serials { Id = 1, Qty = 30, SRNo = "SR-001" },
new Serials { Id = 2, Qty = 70, SRNo = "SR-002" }
};
decimal? QtyToBeIssued = 50;
foreach (var item in serials)
{
if (QtyToBeIssued > item.Qty)
{
QtyToBeIssued = QtyToBeIssued - item.Qty;
item.Qty = 0;
}
else
{
item.Qty = item.Qty - QtyToBeIssued;
}
}

Is there a way to merge two array of objects with same keys, summing up the other property's value?

I'm trying to merge two arrays and sum the values having the same keys. Is it possible to do so?
public struct BassoValues
{
public int BassoId { get; set; }
public decimal Amount { get; set; }
public BassoValues(int bassoId, decimal amount)
{
BassoId = bassoId;
Amount = amount;
}
}
var arrayOne = new BassoValues[4]
arrayOne[0] = new BassoValues() { BassoId = 1, Amount = 1};
arrayOne[1] = new BassoValues() { BassoId = 2, Amount = 10};
arrayOne[2] = new BassoValues() { BassoId = 3, Amount = 20};
arrayOne[3] = new BassoValues() { BassoId = 4, Amount = 30};
var arrayTwo = new BassoValues[4]
arrayTwo[0] = new BassoValues() { BassoId = 1, Amount = 1};
arrayTwo[1] = new BassoValues() { BassoId = 2, Amount = 10};
arrayTwo[2] = new BassoValues() { BassoId = 3, Amount = 20};
arrayTwo[3] = new BassoValues() { BassoId = 4, Amount = 30};
I want to achieve the following result.
var arrayFinal = new BassoValues[4]
arrayFinal[0] = new BassoValues() { BassoId = 1, Amount = 2};
arrayFinal[1] = new BassoValues() { BassoId = 2, Amount = 20};
arrayFinal[2] = new BassoValues() { BassoId = 3, Amount = 40};
arrayFinal[3] = new BassoValues() { BassoId = 4, Amount = 60};
This is how I am trying to achieve the result:
for (int i = 0; i < arrayOne.Length; i++)
{
for (int j = 0; j < arrayTwo.Length; j++)
{
if (arrayOne[0].BassoId == arrayTwo[0].BassoId)
{
var bassoId = arrayOne[0].BassoId;
var sum = arrayOne[0].Amount + arrayTwo[0].Amount;
arrayFinal[0] = new BassoValues() { bassoId, sum};
}
}
}
It'll work in cases when some ids aren't contained in both arrays and if ids can repeat inside one array as well.
var result = arrayOne.Concat(arrayTwo).GroupBy(x => x.BassoId)
.Select(x => new BassoValues(x.Key, x.Sum(y => y.Amount)))
.ToArray();
One solution would be to join the arrays using the Id:
var sumarray = (from a1 in arrayOne
join a2 in arrayTwo on a1.BassoId equals a2.BassoId
select new BassoValues {BassoId = a1.BassoId, Amount = a1.Amount + a2.Amount}).ToArray();
EDIT: In case that each array can contain multiple entries with the same ID and you want to sum them up then the linq-join solution will not suffice anymore. You could group by the id and calculate the sums per id in a loop:
List<BassoValues> Result = new List<BassoValues>();
foreach (var element in arrayOne.GroupBy(x => x.BassoId))
{
BassoValues temp = new BassoValues {BassoId = element.Key};
temp.Amount = arrayTwo.Where(x => x.BassoId == temp.BassoId).Sum(x => x.Amount) + element.Sum(x => x.Amount);
Result.Add(temp);
}
You say your arrays' sizes are fixed to 4.
var arrayFinal = new BassoValues[4]; // create final array
// loop each array
for (int i = 0; i < 4; i++)
{
int amount = arrayOne[i].Amount + arrayTwo[i].Amount;
arrayFinal[i] = new BassoValues() { BassoId = (i+1), Amount = amount };
}

Partition using Linq

Here is my problem, I have a query result set that looks like this:
id_1 - 0 - datetime - gps coordinates
id_2 - 0 - datetime - gps coordinates
id_3 - 1 - datetime - gps coordinates
id_4 - 1 - datetime - gps coordinates
id_5 - 1 - datetime - gps coordinates
id_6 - 1 - datetime - gps coordinates
id_7 - 0 - datetime - gps coordinates
id_8 - 0 - datetime - gps coordinates
id_9 - 0 - datetime - gps coordinates
id_10 - 0 - datetime - gps coordinates
id_11 - 1 - datetime - gps coordinates
id_12 - 1 - datetime - gps coordinates
id_13 - 0 - datetime - gps coordinates
id_14 - 0 - datetime - gps coordinates
This, obviusly returns a list, but I would like to have the sets with value 1 in the second column kept in a list of lists, where each set of lists is one that previously had a 0.
It would look something like this:
List1: [id_3], [...] , [id_6]
List2: [id_11], [...], [id_12]
I dont know the number of elements with 0 or 1 so this has to be generic in that sense
I'm using C# 4.5, and was thinking of using Linq to do this, instead of the old fashioned foreach.
Can anyone point me in the right direction?
I don't think there are something builtin in the framework but you can create an extention method for it :
public static class LinqHelper
{
public static IEnumerable<List<Item>> Partition(this IEnumerable<Item> source, Func<Item, bool> selector)
{
List<Item> currentList = new List<Item>();
foreach (var item in source)
{
if (selector(item))
{
currentList.Add(item);
}
else if (currentList.Count != 0)
{
yield return currentList;
currentList = new List<Item>();
}
}
if (currentList.Count != 0)
{
yield return currentList;
}
}
}
public class Item
{
public int Id { get; set; }
public int Val { get; set; }
}
void Main()
{
var list = new List<Item>(){
new Item{ Id = 1, Val = 0 },
new Item{ Id = 2, Val = 0 },
new Item{ Id = 3, Val = 1 },
new Item{ Id = 4, Val = 1 },
new Item{ Id = 5, Val = 1 },
new Item{ Id = 6, Val = 1 },
new Item{ Id = 7, Val = 0 },
new Item{ Id = 8, Val = 0 },
new Item{ Id = 9, Val = 0 },
new Item{ Id = 10, Val = 0 },
new Item{ Id = 11, Val = 1 },
new Item{ Id = 12, Val = 1 },
new Item{ Id = 13, Val = 0 },
new Item{ Id = 14, Val = 0 },
};
var result = list.Partition(i => i.Val == 1).Where(i => true).ToList();
}
If you're looking to avoid foreach, here's a way to do it with LINQ's Aggregate extension.
Given the following class:
public class SomeType
{
public int Id {get;set;}
public int Val {get;set;}
}
and having generated the following items:
var items = new List<SomeType>();
for(var i = 1; i <= 14; i++)
{
var val = 0;
if((3 <= i && i <= 6) || (11 <= i && i <= 12))
val = 1;
items.Add(new SomeType { Id = i, Val = val});
}
You can get the List of Lists of items with a value of 1 like so:
var grouped = items.Aggregate(new List<List<SomeType>>() { new List<SomeType>() },
(acc,elem) =>
{
if(elem.Val == 0 && acc.Last().Count != 0)
acc.Add(new List<SomeType>());
else if(elem.Val == 1)
acc.Last().Add(elem);
return acc;
}, acc => acc.Where(x => x.Count != 0));
int groupNum = 1;
foreach (var group in grouped)
{
Console.WriteLine($"Group {groupNum++}");
foreach (var item in group)
Console.WriteLine($"{item.Id} - {item.Val}");
}
/* output:
Group 1
3 - 1
4 - 1
5 - 1
6 - 1
Group 2
11 - 1
12 - 1
*/
This assumes that it's okay to add entries with the 1 value before a 0 value has occurred, and I'm not sure that's it's especially more readable than using a foreach, and you would likely be better off implementing an extension method that would likely use foreach anyways.
Try this solution;
var prev = 0;
List<int> bag = null;
var result = new List<List<int>>();
foreach(var item in list)
{
if(item.Val == 1)
{
if(prev == 0)
{
if(bag != null)
result.Add(bag);
bag = new List<int>();
}
bag.Add(item.Id);
}
prev = item.Val;
}
if(bag != null)
result.Add(bag);
result.ForEach(x => {
Console.WriteLine(String.Join(", ", x));
});
//3, 4, 5, 6
//11, 12

Creating Multilevel List from a list of variables with sorting

class Dimensions
{
public int b { get; set; }
public int d { get; set; }
public int CutLength { get; set; }
}
Public void FramingID()
{
var DimList = new List<Dimensions>();
DimList.Add(new Dimensions { b = 2, d = 4, CutLength=10});
DimList.Add(new Dimensions { b = 10,d = 5, CutLength=20});
DimList.Add(new Dimensions { b = 4, d = 6, CutLength=30});
DimList.Add(new Dimensions { b = 4, d = 2, CutLength=40});
DimList.Add(new Dimensions { b = 2, d = 2, CutLength=50});
DimList.Add(new Dimensions { b = 6, d = 4, CutLength=60});
DimList.Add(new Dimensions { b = 2, d = 2, CutLength=70});
DimList.Add(new Dimensions { b = 2, d = 5, CutLength=80});
DimList.Add(new Dimensions { b = 6, d = 2, CutLength=80});
DimList.Add(new Dimensions { b = 2, d = 2, CutLength=50});
var Order = from m in DimList orderby m.b, m.d, m.CutLength select m;
var Order = from m in DimList orderby m.b, m.d, m.CutLength select m;
foreach (var n in Order)
{
Console.WriteLine( n.b.ToString() + " x " + n.d.ToString() + " x " + n.CutLength.ToString());
}
}
result:
2 x 2 x 50
2 x 2 x 50
2 x 2 x 70
2 x 4 x 10
2 x 5 x 80
4 x 2 x 40
4 x 6 x 30
6 x 2 x 80
6 x 4 x 60
10 x 5 x 20
I am trying to create a multilevel list using the same logic in the code above but the difference is that the values in the list are not predefined values a. The result intended in the code below is the same as the code above but the values cannot be predefined
They are values that require to be searched from a group of elements and then be added to the list and be arranged in ascending order accordingly
How can I add the values from the list as integers without using a for loop or a foreach loop as both will no work with the ordering as values will be added separately
Thanks
class Dimensions
{
public int b { get; set; }
public int d { get; set; }
public int CutLength { get; set; }
}
Public void FramingID()
{
var doc = Application.ActiveUIDocument.Document;
FilteredElementCollector Collector = new FilteredElementCollector(doc);
ICollection<Element> StructuralFraming = Collector.OfClass(typeof(FamilyInstance)).OfCategory(BuiltInCategory.OST_StructuralFraming).ToList();
List<int> bIntegerList = (from Element element in StructuralFraming select Convert.ToInt32(doc.GetElement(element.GetTypeId()).LookupParameter("b").AsValueString())).ToList();
List<int> dIntegerList = (from Element element in StructuralFraming select Convert.ToInt32(doc.GetElement(element.GetTypeId()).LookupParameter("d").AsValueString())).ToList();
List<int> ClIntegerList = (from Element element in StructuralFraming select Convert.ToInt32(element.LookupParameter("Cut Length").AsValueString())).ToList();
var DimList = new List<Dimensions>();
DimList.Add(new Dimensions { b = bIntegerList, d = dIntegerList, CutLength = ClIntegerList});
var Order = from m in DimList orderby m.b, m.d, m.CutLength select m;
foreach (var n in Order)
{
TaskDialog.Show("TEST", n.b.ToString() + " x " + n.ToString() + " x " + n.ToString());
}
}
List<int> bIntegerList = new List<int> { 2, 5, 6, 3, 4 };
List<int> dIntegerList = new List<int> { 20, 60, 30, 40, 50 };
List<int> ClIntegerList = new List<int> { 300, 300, 200, 500, 600 };
var wrapperList = bIntegerList.Zip(dIntegerList, (b, d) => new { b, d });
var dimListReal = wrapperList.Zip(ClIntegerList, (w, cl) => new Dimensions() { b = w.b, d = w.d, CutLength = cl });
var Order = from m in dimListReal orderby m.b, m.d, m.CutLength select m;
foreach (var n in Order)
{
Console.WriteLine("Test working " + n.b.ToString() + " x " + n.d.ToString() + " x " + n.CutLength.ToString());
}
from revit
var doc = Application.ActiveUIDocument.Document;
FilteredElementCollector Collector = new FilteredElementCollector(doc);
ICollection<Element> StructuralFraming = Collector.OfClass(typeof(FamilyInstance)).OfCategory(BuiltInCategory.OST_StructuralFraming).ToList();
List<int> bIntegerList = new List<int> (from Element element in StructuralFraming select Convert.ToInt32(doc.GetElement(element.GetTypeId()).LookupParameter("b").AsValueString())).ToList();
List<int> dIntegerList = new List<int>(from Element element in StructuralFraming select Convert.ToInt32(doc.GetElement(element.GetTypeId()).LookupParameter("d").AsValueString())).ToList();
List<int> ClIntegerList = new List<int>(from Element element in StructuralFraming select Convert.ToInt32(element.LookupParameter("Cut Length").AsValueString())).ToList();
var wrapperList = bIntegerList.Zip(dIntegerList, (b, d) => new { b, d });
var dimListReal = wrapperList.Zip(ClIntegerList, (w, cl) => new Dimensions() { b = w.b, d = w.d, CutLength = cl });
var Order = from m in dimListReal orderby m.b, m.d, m.CutLength select m;
foreach (var n in Order)
{
TaskDialog.Show("Test", n.b.ToString() + " x " + n.d.ToString() + " x " + n.CutLength.ToString());
}
So you must have some identifier that relates the 3 dimensions as part of the same entity. Here we have ElementX that represents a Dimension. It can be b or d or CutLength. Each ElementX has an identifier that binds him to other dimension value. Example, if you submit a new Trio of dimensions it will look like:
ElementX dimensionB = new ElementX { Xvalue = 10 , Id = 999 }
ElementX dimensionD = new ElementX { Xvalue = 80 , Id = 999 }
ElementX dimensionCutLength = new ElementX { Xvalue = 800 , Id = 999 }
And there is the testing code
static void Main(string[] args)
{
List<ElementX> bIntegerList = new List<ElementX> { new ElementX { Xvalue = 6, Id = 77},
new ElementX { Xvalue = 3, Id = 66 },
new ElementX { Xvalue = 8, Id = 65 } };
List<ElementX> dIntegerList = new List<ElementX> { new ElementX { Xvalue = 30, Id = 66},
new ElementX { Xvalue = 60, Id = 77 },
new ElementX { Xvalue = 80, Id = 65 } };
List<ElementX> ClIntegerList = new List<ElementX> { new ElementX { Xvalue = 800, Id = 65},
new ElementX { Xvalue = 600, Id = 77 },
new ElementX { Xvalue = 300, Id = 66 } };
var wrapperList = bIntegerList.Join(dIntegerList,
x => x.Id,
y => y.Id,
(x, y) => new { b = x.Xvalue, d = y.Xvalue, Id = y.Id }).ToList();
var dimList = wrapperList.Join(ClIntegerList,
x => x.Id,
cl => cl.Id,
(x, cl) => new Dimensions { b = x.b, d = x.d, CutLength = cl.Xvalue }).ToList();
var Order = from m in dimList orderby m.b, m.d, m.CutLength select m;
foreach (var n in Order)
{
Console.WriteLine("Test working " + n.b.ToString() + " x " + n.d.ToString() + " x " + n.CutLength.ToString());
}
Output

Dijkstra's Algorithm Issue

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()));
}
}
}
}
}
}
​

Categories

Resources