Get to next element in List - c#

If i have a list of objects and i want to move to the next node with each function call (ie create a "GetNextNode" how would i go about doing this? Right now i have one method which will get the first node of my List and set the currentObj to it and return it (leaving previous node still at null) a flag indicates that we're not dealing with the first node in the list anymore. then i move forward and i want to iterate through the list (using foreach i guess?) to one node past my currentObj. Here is my code:
List<Employee> ListOfEmployees = new List<Employee>();
Employee currEmployeeObj = null;
Employee prevEmployeeObj = null;
foreach (Employee employee in ListOfEmployees)
{
//how do i keep track of the previous and current employee in here?
}
return (currEmployeeObj);
}

I hate to sound like a dinosaur, but since you're implementing with a List anyway, why not iterate over it with for instead of foreach? Integers are really useful for comparisons like i == j + 1

Looks like you really are re-inventing an enumerator:
public IEnumerator<Employee> GetEmployees()
{
foreach (Employee employee in ListOfEmployees)
{
//custom processing here
yield return employee;
}
}
Usage:
var myEnumerator = foo.GetEmployees();
while(myEnumerator.MoveNext())
{
var someEmployee = myEnumerator.Current;
//do something
}
Just as an update here is the full class implementation so you can verify it compiles and works..
public class Foo
{
List<Employee> ListOfEmployees = new List<Employee>();
public Foo()
{
ListOfEmployees.Add(new Employee());
}
public IEnumerator<Employee> GetEmployees()
{
foreach (Employee employee in ListOfEmployees)
yield return employee;
}
}

(As an academic exercise, the other answers are probably more appropriate here: )
You could create an extension method like so:
public static IEnumerable<Tuple<T, T>> ToPairs<T>(this IEnumerable<T> enumerable)
{
using (var enumerator = enumerable.GetEnumerator())
{
if (enumerator.MoveNext())
{
var previous = enumerator.Current;
while (enumerator.MoveNext())
{
var current = enumerator.Current;
yield return new Tuple<T, T>(previous, current);
previous = current;
}
}
}
}
To return you a tuple containing pairs of elements.
Which would be used like:
foreach (var pair in ListOfEmployees.ToPairs())
{
Employee prevEmployee = pair.Item1;
Employee currEmployeeObj = pair.Item2;
}

http://msdn.microsoft.com/en-us/library/system.collections.ienumerator.aspx
The link above this line of text has what will work to solve my issue.
Thanks all for the responses and help! Upvoted those who tried to help and had something to offer

Related

Find tree item in c#

I have a page in which a user can select a child of a child from a tree hierarchy in Xamarin Forms. After saving, once a user clicks the edit button, I need to loop over all the items to set the user's selected value again
For example:
public class A
{
public string Id {get;set;}
public string Name {get;set;}
public List<A> Items{get;set;}
}
In the VM, I have a method to initialize object A1 of type A. I need to loop over all the children of A to match a value of A to that of the selected Id
private A GetA(string id, List<A> items)
{
foreach (var a in items)
{
if (a.Id == id)
{
return a;
}
else
{
if (a.Items.Count > 0)
{
return GetA(id, a.Items);
}
}
}
return null;
}
So far, I wrote a recursive function that only loops on the first child of every A. Thus, can anyone provide me with a better solution?
The problem is, that you are not further iterating over the other items in the list, when a.Id != id and a.Items.Count > 0. You should instead save the result of the recursive GetA and only if it's not null return it, otherwise keep looping. Otherwise you would just loop until the first branch and then recursively only ever search all the first branches, but not any other ones.
private A GetA(string id, List<A> items)
{
foreach (var a in items)
{
if (a.Id == id)
{
return a;
}
// You could also remove this if and just call GetA directly,
// since GetA(id, a.Items) with an empty list,
// will always return null
if (a.Items.Count > 0)
{
var innerA = GetA(id, a.Items);
if (innerA != null) {
return GetA(id, a.Items);
}
}
}
return null;
}

How can I use foreach to look one variable ahead in the datatable with conditionals in C#?

You guys helped me out a lot with my last question and now I have another.
I am new to C# and I have to iterate through a datatable to count transactions for different states. However, I have to remove duplicate transactions. I have something similar in javascript where I took one variable ahead in the table and if it matches the current variable then it will subtract one from the counter.
How could I do this in C#? Here is what I am trying to far but with no success:
if (row["State"].ToString().Contains("CA")) //Looks for CA state in the "state" column, however, it appears to not be finding it?
{
californiaTransactions2021 += 1;
if(row["InvNum"].ToString() == row["InvNum"]+1.ToString())
{
californiaTransactions2021 -= 1;
}
Here is what my datatable looks like:
As you can see, some invoice numbers are the same for California and they must be subtracted for the counter. What is the correct syntax for C# to do this in the loop?
If I needed to look ahead, and I needed to use foreach (rather than by index with for, which could use "index+1" to check the next row), then I would do something like this to preserve each row for one iteration and effectively trail my view of the current row by one cycle:
DataRow cachedRow = null;
foreach(var row in MyTable.Rows)
{
if (cachedRow != null)
{
var currentRow = cachedRow;
var nextRow = row;
// Do whatever you want with these two rows
}
cachedRow = row;
}
// Don't forget to also check the final row (cachedRow) here
Note that some iterators cycle through and return a mutation of the same object for each iteration. In this situation you'll need to make sure you're making a deep copy when you set the cachedRow.
You can make a custom enumeration:
static class Extensions
{
public static IEnumerable<(T current, T? next)> WithNext<T>(this IEnumerable<T> enumerable)
{
using var enumerator = enumerable.GetEnumerator();
if(!enumerator.MoveNext()) yield break;
var current = enumerator.Current;
// optional:
//yield return (default, current);
while (enumerator.MoveNext())
{
var next = enumerator.Current;
yield return (current, next);
current = next;
}
// optional:
//yield return (current, default);
}
}
Here is how it might be used:
record Invoice
{
public int InvoiceNumber { get; set; }
public DateTime Date { get; set; }
public double Amount { get; set; }
public string State { get; set; }
}
public void DoStuff()
{
var invoices = ReadInvoiceFile("Your/Path/Here.csv");
var ca2021Invoices = invoices.Where(i => i.Date.Year == 2021 && i.State.Contains("CA"));
foreach (var (thisInvoice, nextInvoice) in ca2021Invoices.WithNext())
{
//do your stuff comparing each invoice to the next
}
}
private List<Invoice> ReadInvoiceFile(string path)
{
//realistically you would use a 3rd party library to do this
}

get tree Like Class children using recursion

I built a class Cluster as follow:
public class Cluster
{
List<Cluster> lstChildClusters=new List<Cluster>();
public List<Cluster> LstChildClusters
{
get { return lstChildClusters; }
set { lstChildClusters = value; }
}
public classA alr;
}
My goal is to build a function that gets all the grandchildren of an object of Cluster type.Basically a father can have 0 or more sons which can have at their turn 0 or more sons.
I tried to build a recursive function but all it gives back is only one grandchild using the code down below.
Here is the function I built:
public List<classA> getLevel0Clusters(Cluster cluster,List<classA> list)
{
if (cluster.LstChildClusters.Count == 0)
{
list.Add(cluster.alr);
return (list);
}
else
{
for (int i = 0; i < lstChildClusters.Count - 1; i++)
{
return (lstChildClusters[i].getLevel0Clusters(lstChildClusters[i], list));
}
return (lstChildClusters[0].getLevel0Clusters(lstChildClusters[0], list));
}
}
I am using those instances for debugging:
Cluster father = new Cluster();
father.Alr = new Alarm("father");
Cluster son1 = new Cluster();
son1.Alr = new Alarm("son1");
Cluster son2 = new Cluster();
son2.Alr = new Alarm("son2");
Cluster grandson1 = new Cluster();
grandson1.Alr = new Alarm("grandson1");
Cluster grandson2 = new Cluster();
grandson2.Alr = new Alarm("grandson2");
father.LstChildClusters.Add(son1);
father.LstChildClusters.Add(son2);
son1.LstChildClusters.Add(grandson1);
son1.LstChildClusters.Add(grandson2);
List<classA> lst=new lst<ClassA>();
lst=father.getLevel0Clusters(father, father.LstAlarms);
Does anybody has any clue on how to troubleshoot this problem?
Thank you in advance
There are a number of problems with your existing code, so I've done a bit of refactoring to make your program simpler.
But first, to answer your direct question, the problem with your existing method is that you're calling return before you finish aggregating all of the results. Your code looks at grandfather and sees that it has children so it enters the for loop and recursively calls itself for son1. It sees that son1 has children so enters the for loop and recursively calls itself for grandson1 which doesn't have children so it adds grandson1 to the list and then returns. The outer call returns after finding the first value so the next two levels up just return. Hence the list only has grandson1.
So, to refactor your code: The getLevel0Clusters method does not need to pass in a Cluster (as it is defined in the Cluster class it can use this) and a List<classA> (as it can generate one as needed).
So your getLevel0Clusters can become simply this:
public List<classA> getLevel0Clusters()
{
return new[] { this.alr, }
.Concat(this.LstChildClusters
.SelectMany(child => child.getLevel0Clusters()))
.ToList();
}
In order to get everything to compile I modified your sample code to be this:
Cluster father = new Cluster();
father.alr = new classA("father");
Cluster son1 = new Cluster();
son1.alr = new classA("son1");
Cluster son2 = new Cluster();
son2.alr = new classA("son2");
Cluster grandson1 = new Cluster();
grandson1.alr = new classA("grandson1");
Cluster grandson2 = new Cluster();
grandson2.alr = new classA("grandson2");
father.LstChildClusters.Add(son1);
father.LstChildClusters.Add(son2);
son1.LstChildClusters.Add(grandson1);
son1.LstChildClusters.Add(grandson2);
List<classA> lst = father.getLevel0Clusters();
...and your classes as this:
public class Cluster
{
List<Cluster> lstChildClusters = new List<Cluster>();
public List<Cluster> LstChildClusters
{
get { return lstChildClusters; }
set { lstChildClusters = value; }
}
public classA alr;
public List<classA> getLevel0Clusters()
{
return new[] { this.alr, }
.Concat(this.LstChildClusters
.SelectMany(child => child.getLevel0Clusters()))
.ToList();
}
}
public class classA
{
public string Name;
public classA(string name)
{
this.Name = name;
}
}
When I ran your sample code I got this result out:
The problem is that as soon as you find one offspring, you return to the calling program. The value of Count has no effect other than 0 versus positive: you enter the loop, call lstChildClusters[0].getLevel0Clusters(lstChildClusters[0], and return that value without bothering to increment i and continue the loop.
Instead, your for loop has to add each return value to the list. After the loop is done, you can return to the calling program.

Problem with circular reference list

I have a small problem and I would like to get your opinion.
I'm dealing with documents than can reference other documents. Starting from any document, I need to get the id of all the documents this document references. The problem is that the circular references are allowed so if A ref B ref C, again C can ref A and I get in the loop.
How can I solve this problem in C#?
An small example:
Let suppose that this is a class that represents a document:
public class Document
{
public Document(int id)
{
this.ID = id;
}
private int m_ID;
public int ID
{
get { return m_ID; }
set { m_ID = value; }
}
private List<Document> m_Children = new List<Document>();
public List<Document> Children
{
get { return m_Children; }
set { m_Children = value; }
}
private List<Document> m_Parent = new List<Document>();
public List<Document> Parent
{
get { return m_Parent; }
set { m_Parent = value; }
}
public Document AddChild(Document child)
{
child.Parent.Add(this);
this.Children.Add(child);
return child;
}
public Document AddChild(int child)
{
Document d = new Document(child);
return AddChild(d);
}
}
Now let's create a Document class that has some references:
public static Document CreateReferences()
{
Document d = new Document(1);
Document temp = d.AddChild(2);
for (int i = 3; i < 6; i++)
{
temp = temp.AddChild(i);
}
temp.AddChild(d);
return d;
}
Now I need to implement a method in Document class like
public List<int> GetReferencedDocuments()
{ }
What is the best way to do that? Any specific algorithm can be implemented?
Any suggestion is well accepted!
Thanks
Any tree-traversal algorithm would be fine.
As well as a list of docs you're going to build up, maintain a queue of documents you've yet to check, add the first document to that list.
Then, while the queue isn't empty, get the next doc, if it's not already in your list, then add it, and add all referenced docs to your queue.
List<Document> FoundDocs = new List<Documents();
Queue<Document> DocsToSearch = new Queue<Document>();
DocsToSearch.Enqueue(StartDoc);
while(DocsToSearch.Count != 0)
{
Document Doc = DocsToSearch.Dequeue();
if(!FoundDocs.Contains(Doc))
{
FoundDocs.Add(Doc);
foreach(var ChildDoc in Doc.Children)
{
DocsToSearch.Enqueue(ChildDoc);
}
}
}
The best way is to do a depth first search or a breadth first search
There are two main approaches to resolving this sort of recursive search on recursive data: marking or recording.
Marking: every time you list a document, flag it as viewed. Do not process flagged documents.
So your GetReferenceDocuments would look a little like this:
GetReferencedDocuments(startpoint)
if(startpoint.flagged) return null
startpoint.flag
new list result =startpoint
foreach(subdocument in
documents.children)
result.append(getreferenceddocuments(subdocuments))//
if not null
Recording: a similar approach, but the flag indicators are replaced by a list of already referenced documents ( a separate list of ids maybe ), and the flag check is a search on this list for this document.
Either way will work, depending on your objects, size and scale. If you cannot change the document objects, you will have to list them. If you have, potentially, 1M documents in your scan, you do not want to list them.
Example implementation:
public List<int> GetReferencedDocuments()
{
var referencedIds = new List<int>();
var queue = new Queue<Document>(this);
while (queue.Count > 0)
{
var newDocuments = queue.Dequeue().Children
.Where(d => !referencedIds.Contains(d.ID))
foreach (Document newDocument in newDocuments)
{
queue.Enqueue(newDocument);
referencedIds.Add(newDocument.ID);
}
}
return referencedIds;
}

Run a method on all objects within a collection

So I have a collection of Razzies created from a Collection of Bloops. I retrieve this collection using a Linq query. Reference:Linq Select Certain Properties Into Another Object? for the query.
I would like to know if it is possible to run a method on all of the newly created Razzies before returning the collection, or even right after, just without using a for-loop.
I tried this:
Dim results = From item In bloops _
Select New Razzie() With _
{ _
.FirstName = item.FirstName, _
.LastName = item.LastName _
}.UpdateAddress(item.Address)
But it returns nothing.
Russ, this might do what you want. It's a pretty simple approach. If this is not what you want, please expand your question.
This will run the method on each element as you enumerate over them. It will not run the method until you enumerate, but you can safely know that the method will run before you use the data.
EDIT Since you are using a sealed 3rd party class, use extension methods. That's what they're for. ;) Modified code to use extension methods.
class MyArgs { }
class Razzie //pretend this is a 3rd party class that we can't edit
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
static class RazzieExtensions
{
public static Razzie MyMethod(this Razzie razzie, MyArgs args)
{
razzie.FirstName = razzie.FirstName.ToUpper();
return razzie;
}
}
class Program
{
static void Main(string[] args)
{
var bloops = new List<Razzie>
{
new Razzie{FirstName = "name"},
new Razzie{FirstName = "nAmE"}
};
var myArgs = new MyArgs();
var results = from item in bloops
select new Razzie
{
FirstName = item.FirstName,
LastName = item.LastName
}.MyMethod(myArgs);
foreach (var r in results)
Console.WriteLine(r.FirstName);
Console.ReadKey();
}
}
Using a foreach loop after your initial processing is the normal way to do this. If you don't want to use a foreach loop, you'll need to define your own extension method to handle this situation.
I'm not sure what you mean by RunVoid. Void suggests no return yet you assign the results to a value.
Do you RunVoid to execute a method on every item and then return the original collection? If so, there is no built-in method but you can add one like so.
<Extension>
Public Function RunVoid(Of T)(source As IEnumerable(Of T), del As Action(Of T) As IEnumerable(Of T)
For Each cur in source
del(cur)
Next
return source
End Function
Why not just do this the normal, unconvaluted way? You can do a bunch of fancy stuff with extension methods...but your likely breaking the purity rule by performing an update with an extension method...and it makes things difficult to understand too. Try this:
var results = from ... select new { Address = item.Address, Razzie = new Razzie { ... }}
foreach (var result in results)
{
result.Razzie.UpdateAddress(result.Address);
}
If you're looking to abstract away the foreach loop, I'd just write an extension method for IEnumerable<T> that duplicates List<T>'s ConvertAll and ForEach methods, like this:
public static IEnumerable<TOutput> ConvertAll<T, TOutput>(this IEnumerable<T> collection, Converter<T, TOutput> converter)
{
if (converter == null)
throw new ArgumentNullException("converter");
List<TOutput> list = new List<TOutput>();
foreach (T item in collection)
{
list.Add(converter(item));
}
return list;
}
public static void ForEach<T>(this IEnumerable<T> collection, Action<T> action)
{
foreach (T item in collection)
{
action(item);
}
}
Then you could just call something like:
bloops
.ConvertAll(bloop => new Razzie()
{
FirstName = bloop.FirstName,
Lastname = bloop.LastName
})
.ForEach(razzie => razzie.UpdateAddress());

Categories

Resources