How do I show the path of Bfs? - c#

So I'm trying to make BFS algorithm, and I was able to calculate the shortest path distance between each 2 nodes. But the neighbors of each node (i.e node A) is not only nodes it's a dictionary of nodes as a key and a hashset of matches where each two nodes played in. Now, I don't know how to store the path while the BFS is working... This the adjacency function that returns the neighbors of each nodes
Dictionary<string, Dictionary<string, HashSet<string>>> dic= new Dictionary<string, Dictionary < string,, HashSet < string >>>;
public IEnumerable<KeyValuePair<string, HashSet<string>>> adjacentto(string v)
{
return dic[v];
}
And this is my BFS function:
private Dictionary<string, int> dist = new Dictionary<string, int>();
public void BFSDegree(Graph g, string s, string p)
{
Queue<string> q = new Queue<string>();
dist.Add(s, 0);
q.Enqueue(s);
while (q.Count() != 0)
{
string j = q.Dequeue();
//count = 0;
foreach (KeyValuePair<string, HashSet<string>> h in g.adjacentto(j))
{
if (!dist.ContainsKey(h.Key))
{
q.Enqueue(h.Key);
dist.Add(h.Key, 1 + dist[j]);
}
if (j == p)
{
Console.WriteLine(" " + dist[j]);
return;
}
}
}
}
So, what I need it is to go see the path and read the values of the hashset, for example node A and node B played together in 3 matches match 1, match 2, match 7 so this should be the path. So I'm gonna print to the console "The path is either match 1, match 2 or match 7). And the same thing if I had 2 nodes that didn't star in a match together but they both starred with node A in 2 separate matches so the path should be through either of these 2 matches. How do I keep track of the paths and store the path while operating BFS? This is the file I'm reading the graph from.
This is the how I built my graph
And this is what I want to achieve
I was able to achieve the first goal (degree) through using BFS. But now I don't know how to achieve the "chain" or the path. The chain is nothing but the number of the movies in the path so I think if I'm able to save the path (show the path) while the BFS is working I shall be able to achieve the chain. So my problem is the last goal how do I save the path and show it.

In order to find the shortest path from one node to another, you can keep track of parents of each node. for example the graph below, when I run bfs from 0 up to 9, I keep track of each node reached an assign a parent. Once a parent is assigned, I do not reassign. So for example, if I want to find path from 0 to 9 and length I simply backtrack i.e. 9-7-3-1-0 so start from 9's parent and check 7's parent and so forth until you get to start node. We can easily then get the length.
As for the query, when you do something like C/E you can first run bfs to check for the path "which should be 2 going from C-A-E" and of course there could be other paths but I guess shortest path is the best for what you want ?
Anyway, let's assume we choose path C-A-E we can update the Rel. by the number of edges so Rel = 2 and then Chain will be
//Nodes -> [C, A, E]
//Parents ->[C, C, A]
Start from E // which is destination
Get movies of parent // parent is A, returns Movies 2
move to parent // now we are checking A
Get movies of parent // parent is C, returns Movies 1 Movies 7
break;
You break as soon as you reach source or you can do it vice versa
At the end you have Movies 2,1, and 7
A parent is just a predecessor of a node. For example, while you run Bfs if you go from 0 to 1 then 0 is parent of 1
Here is an implementation that I hope will help you understand it a little better.
private Map<Integer, List<Integer>> _adjacencyList;
private Map<Integer, String> _movies; // will store neighbors here
private Queue<Integer> queue;
private int [] visited;
public BaconNumber(int V){// v here is number of vertices
_adjacencyList = new HashMap<Integer, List<Integer>>();
_movies = new HashMap<Integer, String>();
queue = new LinkedList<Integer>();
visited = new int[V];
for(int i = 0; i < V; i++){
_adjacencyList.put(i, new LinkedList<Integer>());// add a linkedlist for each vertex
visited[i] = -1;
}
}
Fill movies here
private void fillNeighbors(){
//0 = A, 1 = B, 2 = C, 3 = D, 4 = E
_movies.put(0, "Z Movie 0 | B Movie 1 Movie 2 Movie 7 | C Movie 1 Movie 7 | D Movie 2 Movie 7 | E Movie 2");
_movies.put(1, "A Movie 1 Movie 2 Movie 7 | C Movie 1 Movie 7 | D Movie 2 Movie 7 | E Movie 2");
_movies.put(2, "A Movie 1 Movie 7 | B Movie 1 Movie 7 | D Movie 7");
_movies.put(3, "E Movie 2 | A Movie 2 Movie 7 | B Movie 2 Movie 7 | C Movie 7");
_movies.put(4, "D Movie 2 | A Movie 2 | B Movie 2 | F Movie 3 | G Movie 3");
}
Get movies. This takes in two parameters. One for where we get the movie from and the other for the node we are looking for. Note that I converted the second parameter to a letter so it looks like what you have
public String getMovies(int s, int v){
String result = "";
// just getting corresponding character
int rem = v % 26;
char l = (char)((int)'A' + rem);
//System.out.println("this is char "+l);
String movie = _movies.get(s);
String [] tokens = movie.split("\\|");
for(int i = 0; i < tokens.length; i++){
String next = tokens[i];
if(next.contains(String.valueOf(l))){
result = next;
break;
}
}
return result;
}
And now the query part
String query(int source, int dest){
List<Integer> nodes = new LinkedList<Integer>();
int i, element;
visited[source] = source;
queue.add(source);
while(!queue.isEmpty()){
element = queue.remove();
i = element;
if(i == dest) break; // we stop as soon as we reach destination
nodes.add(element);
List<Integer> iList = getEdge(i);
System.out.println(i+" -> "+iList);
int x = 0;
while(x < iList.size()){
int index = iList.get(x);
if(visited[index] == -1){
queue.add(index);
visited[index] = i;
}
x++;
}
}
String result = "";
for(int x = dest; x >= 0; x= visited[x]){
if(x == source) break; // we are done
if(visited[x] != -1){
result += getMovies(x,visited[x]); // get predecessor of x movies from x
}
}
return result;
}

Related

Call different list with similar name in a for loop

I have a few lists that are with names: group1, group2, group3...
I need a for loop (lets say for (int i=1; i<=6; i++) and right now I check for example if i is 1 then use group1, if i is 2 use group2 etc... My question is, can I call the list with the 'i' in the end? Like groupi and when i is 1, its group1, when i is 2, its group2 etc. Here is the code:
for (int i = 0; i < groupNum; i++)
{
if (i == 0)
{
foreach (Player p1 in group1)
{
foreach (Player p2 in group1)
{
if (p1 != p2)
{
if (group1.IndexOf(p1) > group1.IndexOf(p2))
{
Game game = new Game(tournamentID, p1.id, p2.id);
game.status = "Pending";
gm.CreateGame(game);
}
}
}
}
}
else if (i == 1)
{
foreach (Player p1 in group2)
{
foreach (Player p2 in group2)
{
if (p1 != p2)
{
if (group2.IndexOf(p1) > group2.IndexOf(p2))
{
Game game = new Game(tournamentID, p1.id, p2.id);
game.status = "Pending";
gm.CreateGame(game);
}
}
}
}
}
else if (i == 2)
{
foreach (Player p1 in group3)
{
foreach (Player p2 in group3)
{
if (p1 != p2)
{
if (group3.IndexOf(p1) > group3.IndexOf(p2))
{
Game game = new Game(tournamentID, p1.id, p2.id);
game.status = "Pending";
gm.CreateGame(game);
}
}
}
}
}
else if (i == 3)
{
foreach (Player p1 in group4)
{
foreach (Player p2 in group4)
{
if (p1 != p2)
{
if (group4.IndexOf(p1) > group4.IndexOf(p2))
{
Game game = new Game(tournamentID, p1.id, p2.id);
game.status = "Pending";
gm.CreateGame(game);
}
}
}
}
}
else if (i == 4)
{
foreach (Player p1 in group5)
{
foreach (Player p2 in group5)
{
if (p1 != p2)
{
if (group5.IndexOf(p1) > group5.IndexOf(p2))
{
Game game = new Game(tournamentID, p1.id, p2.id);
game.status = "Pending";
gm.CreateGame(game);
}
}
}
}
}
else if (i == 5)
{
foreach (Player p1 in group6)
{
foreach (Player p2 in group6)
{
if (p1 != p2)
{
if (group6.IndexOf(p1) > group6.IndexOf(p2))
{
Game game = new Game(tournamentID, p1.id, p2.id);
game.status = "Pending";
gm.CreateGame(game);
}
}
}
}
}
As you can see, the code for different if statements is literally the same but the only difference is in using different lists with similar name (group1, group2..).
In General
This comes up a lot. No; you cannot programmatically build a variable name. By the time the code is compiled the variable names are gone anyway
If you ever have variables with names like
something1
something2
something3
etc, then this is a candidate for using an array but remember arrays start from 0
var something = new Thing[3];
(In your case the Thing is e.g. a Player)
Now you can have a fixed part and a varying part in your name:
Before you had Now you have
-------------- ------------
something1 something[0]
something2 something[1]
something3 something[2]
Arrays can be looped over with a for or foreach, and they can be accessed at random with hard coded indexes like above. Just like your code only having 3 variables named somethingX your array also has a fixed number of 3 values. Arrays don't grow
If you need something that works like an array but does grow, use a List:
var something = new List<Thing>();
This is a list of Thing, just like before you had an array of Thing.
Also, don't forget about dictionaries, which are like lists, in that they grow, but they can be indexed by anything, so you can programmatically build an index, and unlike arrays/lists which are indexed by an incrementing integer, a dictionary can skip out some indexes:
var dict = new Dictionary<int, Thing>();
This means "a dictionary indexed by an int and holding a Thing"
Now, this is possible:
dict[1] = new Thing();
dict[2] = new Thing();
dict[4] = new Thing(); //we skipped
The key can be anything, for example a string:
var dict = new Dictionary<string, Thing>();
dict["something1"] = new Thing();
dict["something2"] = new Thing();
dict["sometheng4"] = new Thing(); //watch out for typos!
You can programmatically build the key:
int x = 1;
dict["something"+x].SomePropertyOfThing = "Hello";
The only thing to note is that dictionary doesn't necessarily store it's contents in any kind of order. If you foreach it you might get the entries out in something2, sometheng4, something1 order. If you need order, you either have to sort the dict.Keys and then use it to access the dictionary, or you use a SortedDictionary or OrderedDictionary depending what you want
In summary, those are the main kinds of collections we use in C#; they have different strengths and weaknesses and choosing which to use in a situation is often an important engineering decision
Final point of note; strive to use plural names when working with collections, as it makes the code easier to reason about
Specifically in this case
In your particular case you're actually looking for an array of arrays, and a bit of LINQ might make your code easier to deal with:
var groups = new []{ group1, group2, group3 };
foreach(var g in groups)
foreach(var p1 in g)
foreach(var p2 in g.Where(p => p.id > p1.id))
gm.CreateGame(new Game(tournamentID, p1.id, p2.id){status = "Pending"});
If you want to make just one tournament for a particular group N, replace the foreach(var g in groups) with var g = groups[N]
This logic you have of "for each player 1, for each player 2, if they aren't the same player, find the index of the player 1, find the index of the player 2, if the one index is less than the two index" contains redundant logic, and it wastes resources finding things it has already found
Saying "for every player1 in the group, for every player2 whose id is greater than player1" cuts all that out. Player 2 must be a different player to Player 1 because their id is greater. There is no need to look up the index; you could shortcut your code to comparing the IDs rather than doing a notequals check then finding indexes then comparing
If your ID values aren't intrinsically comparable in a greater than sense for some reason (I assumed they would be ints) you can use a bit more linq to assign an index i to each player p in a group:
var groups = new []{
group1.Select((p,i) => (p,i)),
group2.Select((p,i) => (p,i)),
group3.Select((p,i) => (p,i))
};
This make a tuple of the player, and the index they're at, so a similar logic as before can work:
foreach(var g in groups)
foreach(var p1t in g)
foreach(var p2t in g.Where(pt => pt.i > p1t.i))
gm.CreateGame(new Game(tournamentID, p1t.p.id, p2t.p.id){status = "Pending"});
This time the Where demands the index i be greater for player 2
You should name your properties using PascalCase, not camelCase
As has already been suggested, you could collect all your groups in an array, and then iterate over that group array:
List<Player>[] groups = new[] { group1, group2, group3, group4, group5, group6 };
foreach (var group in groups)
{
// play games
}
I would like to suggest a simplification of your logic as well. You can achieve the same result using fewer nested loops by only looping through the necessary combinations of player 1 and player 2 in each group.
One way to do this is to:
loop over the players' list indices rather than the Player objects in the lists (i.e. replace your nested foreach (Player p*) loops with nested for (int i*) (player index) loops)
let the outer loop (looping over the indices for player 1) iterate over the current group from 0 to the second-to-last-index
let the inner loop (looping over the indices for player 2) iterate over the current group from one index larger than the index of player 1 to the very last index
Implementation:
foreach (var group in groups)
{
for (int i1 = 0; i1 < group.Count - 1; i1++)
{
Player p1 = group[i1];
for (int i2 = i1 + 1; i2 < group.Count; i2++)
{
Player p2 = group[i2];
Game game = new Game(tournamentID, p1.id, p2.id);
game.status = "Pending";
gm.CreateGame(game);
}
}
}
If we refer to the index of player 1 simply as 1 and the index of player 2 simply as 2, the iterations over a group containing four players can be visualized as follows:
1 2 _ _
1 _ 2 _
1 _ _ 2
_ 1 2 _
_ 1 _ 2
_ _ 1 2
If you rather want the games to be created in the exact same order of player combinations as is done in your original post, the index conditions need to be altered so that p2 always comes before p1 in the group:
2 1 _ _
2 _ 1 _
_ 2 1 _
2 _ _ 1
_ 2 _ 1
_ _ 2 1
This can be achieved by altering the for loop statements slightly:
the index of player 1 goes from 1 to the very last index in the group
the index of player 2 goes from 0 to one index smaller than the index of player 1
foreach (var group in groups)
{
for (var i1 = 1; i1 < group.Count; i1++)
{
//
for (var i2 = 0; i2 < i1; i2++)
{
//
}
}
}
To ensure you are not trying to perform invalid looping on any of the groups, you could alter the foreach statement to consider the length of each group; either by using .Skip(1).Any() from the System.Linq namespace:
//using System.Linq;
foreach (var group in groups.Where(gr => gr.Skip(1).Any()))
{
// play games
}
or by counting the items in each group:
foreach (var group in groups.Where(gr => gr.Count > 1))
{
// play games
}
We're checking that the number of items in each group is greater than 1 (i.e. the number of items is at least 2), seeing as we want to play games with two players at a time.
create a list of grpups
var groups = new List<Group>(){
group1, group1, group3};
now you can do
if(group[i].Indexof.....)
etc
Just make an array of your groups, assuming they are List<Player> below, and iterate over that:
foreach(var grp in new List<Player>[] {group1, group2, group3, group4, group5, group6}) {
foreach (Player p1 in grp)
{
foreach (Player p2 in grp)
{
if (p1 != p2)
{
if (grp.IndexOf(p1) > grp.IndexOf(p2))
{
Game game = new Game(tournamentID, p1.id, p2.id);
game.status = "Pending";
gm.CreateGame(game);
}
}
}
}
}

How do I display a list and a list of lists side by side

I found a code that displays two lists side by side but a list and a list of lists no luck
this is the code of two lists side by side
for (var i = 0; i < bncount; i++)
{
//Console.WriteLine(String.Format("{0,-10} | {1,-10}", hed.ElementAt(i),bin.ElementAt(i)));
Console.WriteLine(String.Format("{0,-10} | {1,-10}", i< hdcount ? hed[i] : string.Empty, i< bncount ? bin[i] : string.Empty));
}
but the string.empty is for lists only and not list of lists and ElementAt() also wouldn't work
I tried using linq with foreach but no success
the hed is a list of strings and bn is a list of lists of a sequence of numbers
my output are as follows
foreach(var r in bin) //0010 1110 1111
foreach(var m in hed) //red blue white
I want to have the following output
red 0010
blue 1110
white 1111
or
red blue white
0 1 1
0 1 1
1 1 1
0 0 1
Any Idea on how to do this in c# in general or in Linq? the methods I tried either resulted on reprinting one value only froma hed and all the vlaues from bin or the opposite
Not sure if I understood the question correctly, I think it would be helpful to extend the code examples including the variables definition. Anyway, if I understood correctly, this would me my approach:
var listOfString = new List<string>( )
{
"red",
"blue",
"white"
};
var listOfArrays = new List<int[]>( )
{
new int[] { 0,0,1,0 },
new int[] { 0,1,1,1 },
new int[] { 1,1,1,1 }
};
// Here you could add a condition in case you are not 100% sure your arrays are of same length.
for( var i = 0; i < listOfString.Count; i++ )
{
var stringItem = listOfString[i];
var arrayItem = listOfArrays[i];
Console.WriteLine( $"{stringItem} {string.Join( null, arrayItem )}" );
}
I would suggest using a different structure for storing your data (considering OOP principles) and the following code for printing the data out:
public class Item
{
public string Name { get; set; }
public List<int> Values { get; set; }
}
public void Print(List<Item> items)
{
foreach (var item in items)
{
Console.WriteLine($"{item.Name} {string.Join("", item.Values)}");
}
}
The first version is not so hard:
string reuslt = string.Join("\n", bin.Zip(hed).Select(x => $"{x.Item1} {x.Item2}"));
With zip, we create an enumerable of tuples, where the n-th tuple has the n-th element of bin and the n-th element of hed. You can just concatenate those two items.
The second version is a bit more complex:
result = string.Join("\t",hed) + "\n" +
string.Join("\n",Enumerable.Range(0, bin.First().Length)
.Select(x => string.Join("\t\t", bin.Select(str => str[x]))));
We create the heading line by just joing the hed strings. Then we create an enumerable of numbers which represent the indexes in the string. The enumerable will be 0, 1, 2, 3. Then we take the char with index 0 of each string of the bin list, then the char with index 1 of each string of the bin list and so on.
Online demo: https://dotnetfiddle.net/eBQ54N
You can use a dictionary:
var hed = new List<string>(){"red", "blue", "white"};
var bin = new List<string>(){ "0010", "1110", "1111" };
Dictionary<string, string> Dic = new Dictionary<string, string>();
for (int i = 0; i < hed.Count; i++)
{
Dic.Add(hed[i],bin[i]);
}
foreach (var item in Dic)
{
Console.WriteLine(item.Key+" "+item.Value);
}
Console.ReadKey();

Combining Two Lists Based on first 6 Characters

I have two lists (Current & New). Current can contain 100,000+ strings each starting with a unique number. New can contain anywhere between 50 and 200 strings each with a unique number.
If New contains a string starting with the same 6 characters it should replace the same entry in Current. Any new entries that don't exist in Current but exist in New should be added to Current. I've considered Union, Concat and Intersect, but each only deal with the entire string.
Is there some way to compare just the first 6 characters of an item in a list and replace the entry in Current if found it exists in New?
Perhaps the easiest way to visualise the above is:
Current
123456 66 Park Avenue Sydney
New
123456 88 River Road Sydney
The result in Current needs to be
123456 88 Park Avenue Sydney
If Current.Union(New, first X characters) was possible it would be perfect.
Any suggestions on Combine the two lists without duplicates based on the first 6 characters would be greatly appreciated.
string.StartsWith is what you are looking for.
This should do it. Note I have used two dictionaries because there might be duplicates to be replaced, if not, you can use one.
public static void Coder42(List<string> current, IEnumerable<string> news)
{
Dictionary<string, string> newDict = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
Dictionary<string, string> unfound = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
foreach (var n in news)
{
if (n.Length < 6) throw new Exception("Too short");
var ss = n.Substring(0, 6);
if (newDict.ContainsKey(ss)) throw new Exception("Can't be too new.");
newDict[ss] = n;
unfound[ss] = n;
}
for (int i = 0; i < current.Count; i++)
{
var s = current[i];
if (s.Length >= 6)
{
var ss = s.Substring(0, 6);
if (newDict.TryGetValue(ss, out string replacement))
{
current[i] = replacement;
unfound.Remove(ss);
}
}
}
foreach(var pair in unfound)
current.Add(pair.Value);
}
And tested using:
var current = new List<string>();
current.Add("123456 a");
current.Add("123457 b");
current.Add("123458 c");
var news = new List<string>();
news.Add("123457 q");
news.Add("123456 p");
news.Add("123459 z");
Coder42(current, news);
foreach (var s in current) Console.WriteLine(s);
Console.ReadLine();
Gives:
123456 p
123457 q
123458 c
123459 z

Regex: Multiple captures in multiple captures

I've a regular expression that works perfect.
^SENT KV(?<singlelinedata> L(?<line>[1-9]\d*) (?<measureline>\d+)(?: (?<samplingpoint>\d+))+)+$
My Input string looks like this:
SENT KV L1 123 1 2 3 L2 456 4 5 6
The only question is: How to get the context of all captures of group "samplingpoint"?
This group contains 6 captures but I need the context information too. There are three captures in the first capture of group "singlelinedata" and three in the second capture. How to get this information?
The capture of a group doesn't contain a property containing all captures of contained groups.
I know that I can write a single regex to match the whole string an perform a second regex to parse all "singlelinedata"-captures.
I'm looking for a way that works with the specified regex.
Hope someone can help me.
void Main()
{
string data = #"SENT KV L1 123 1 2 3 L2 456 4 5 6";
Parse(data).Dump();
}
public class Result
{
public int Line;
public int MeasureLine;
public List<int> SamplingPoints;
}
private Regex pattern = new Regex(#"^SENT KV(?<singlelinedata> L(?<line>[1-9]\d*) (?<measureline>\d+)(?: (?<samplingpoint>\d+))+)+$", RegexOptions.Multiline);
public IEnumerable<Result> Parse(string data)
{
foreach (Match m in pattern.Matches(data))
{
foreach (Capture c1 in m.Groups["singlelinedata"].Captures)
{
int lineStart = c1.Index;
int lineEnd = c1.Index + c1.Length;
var result = new Result();
result.Line = int.Parse(m.Groups["line"].CapturesWithin(c1).First().Value);
result.MeasureLine = int.Parse(m.Groups["measureline"].CapturesWithin(c1).First().Value);
result.SamplingPoints = new List<int>();
foreach (Capture c2 in m.Groups["samplingpoint"].CapturesWithin(c1))
{
result.SamplingPoints.Add(int.Parse(c2.Value));
}
yield return result;
}
}
}
public static class RegexExtensions
{
public static IEnumerable<Capture> CapturesWithin(this Group group, Capture capture)
{
foreach (Capture c in group.Captures)
{
if (c.Index < capture.Index) continue;
if (c.Index >= capture.Index + capture.Length) break;
yield return c;
}
}
}
Edit: Rewritten as an extension method on Group.
There's no concept of "subgroups" in the regex API. A group can have multiple captures, but you can't know which samplingpoint belongs to which line.
You only option is to use the character index to calculate it yourself.
One way without doing lots of index matching and keeping a single regex is to change the capture groups to all have the same name. The nested captures actually get pushed onto the stack first so you end up with an array like this:
["1", "123", "1", "2", "3", "L1 123 1 2 3", "2", "456", "4", "5", "6", "L2 456 4 5 6"]
Then it's just a matter of some LINQ craziness to split the result into groups when a capture containing an L is found and then pulling out the data from each group.
var regex = new Regex(#"^SENT KV(?<singlelinedata> L(?<singlelinedata>[1-9]\d*) (?<singlelinedata>\d+)(?: (?<singlelinedata>\d+))+)+$");
var matches = regex.Matches("SENT KV L1 123 1 2 3 L2 456 4 5 6 12 13 L3 789 7 8 9 10");
var singlelinedata = matches[0].Groups["singlelinedata"];
string groupKey = null;
var result = singlelinedata.Captures.OfType<Capture>()
.Reverse()
.GroupBy(key => groupKey = key.Value.Contains("L") ? key.Value : groupKey, value => value.Value)
.Reverse()
.Select(group => new { key = group.Key, data = group.Skip(1).Reverse().ToList() })
.Select(item => new { line = item.data.First(), measureline = item.data.Skip(1).First(), samplingpoints = item.data.Skip(2).ToList() })
.ToList();
Based on the answer of Markus Jarderot I wrote an extension method for groups that takes a capture and returns all captures of that group within the specified capture.
The extension method looks like this:
public static IEnumerable<Capture> CapturesWithin(this Group source, Capture captureContainingGroup)
{
var lowerIndex = captureContainingGroup.Index;
var upperIndex = lowerIndex + captureContainingGroup.Length - 1;
foreach (var capture in source.Captures.Cast<Capture>())
{
if (capture.Index < lowerIndex)
{
continue;
}
if (capture.Index > upperIndex)
{
break;
}
yield return capture;
}
}
Usage of this method:
foreach (var capture in match.Groups["singlelinedata"].Captures.Cast<Capture>())
{
var samplingpoints = match.Groups["samplingpoint"].CapturesWithin(capture).ToList();
...

Algorithm find every child by idParent property

I have a table named Drinking.
Here is how it looks:
Name idCategory idParentCategory
drink 1 1
alcohol 2 1
nonalcohol 3 1
tea 5 3
juice 4 3
sparkling 6 4
nonsparkling 7 4
pepsi 8 6
schweppes 9 6
wine 10 2
beer 11 2
Now, the input is idCategory. As you can see there isn't property idChildren. What I am trying to do is find the ids of the children.
For example, if the input is 1, the output should be 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11.
Here is what I tried:
public void myMethod()
{
List<Drinking> drinkingList= (from d in myEntities.Drinking
select d).ToList();
foreach (var d in drinkingList)
{
if (d.Drinking2Reference.EntityKey != null)
{
s = c.Drinking2Reference.EntityKey.EntityKeyValues[0].Value.ToString();
idPD = Int32.Parse(s);
//get idParent
if (idPC == idCat)
{
//if idParent is equal as the input, put this idCategory
//in a list of integers.
//Now, here comes the tricky part.
//I should continue with this loop AND repeat this for
//every child of idPC.
//Where to put the call for this method?
//Where to put the return statement?
//Here is what I'm doing
myMethod(idPC);
}
else
{
myMethod(idPC);
}
}
}
}
My goal is to fill a list with the ids of the children and greatchildren
public void myMethod(int value)
{
List<int> intList = new List<int>();
List<Drinking> drinkingList= (from d in myEntities.Drinking
select d).ToList();
foreach (var d in drinkingList)
{
if (d.Drinking2Reference.EntityKey != null)
{
if(d.idCategory == value)
intList.Add(value);
else {
for(int i=0; i < intList.Count; i++) {
if(intList.ElementAt(i) == d.idParentCategory)
intList.Add(d.idCategory);
}
}
}
}
//Print numbers
}
I haven't tested this, but I feel like it should work. Feel free to comment if you catch something. Also, the table has to be sorted by idParentCategory for this to work. I will also say that with this situation I would recommend you look into using trees rather than a table.

Categories