list in recursive function is getting reset - c#

Inside a recursive function I append elements to a list (IEnumerable) that I gave the function as a parameter.
Somethig like this:
public class FooObject {
private string Name;
private List<FooObject>? Childs;
public void RecursiveFunction(IEnumerable<FooObject> excludeList) {
if (!excludeList.Any(x => x.Name == this.Name))
return;
excludeList = excludeList.Append(this);
foreach (var child in this.Childs) {
child.RecursiveFunction(excludeList);
}
}
}
The problem is that for example in a depth of 3 it appended an element to the list and has no child elements so finishes and goes up to depth 2 again and there the appended element from depth 3 isn't in the list anymore.
Is this behavior intended or do I missunderstand something in the concept of function parameters and pointers?

You assign a different enumerable to the variable excludeList, similar as:
var excludeList = originalList;
excludeList = otherList; // now originalList is not changed, of course
You need to let the method take a real list and use it's Add method
public void RecursiveFunction(List<FooObject> excludeList) {
if (excludeList.Any(x => x.Name == this.Name))
return;
excludeList.Add(this);
foreach (var child in this.Childs) {
child.RecursiveFunction(excludeList);
}
}
If you want to support more collection as just a List<T> you could allow ICollection<T>.

Related

Creating a list composed of object property references

I am trying to do the following thing:
- From within a 1st method, I am going through a bunch of objects (of same type) and extracting pointers to specific properties into a list
- This list will then be fed to a another method elsewhere in my program at some point in time and has to modify all the properties (as per provided list) of the original objects
In other words, say we have the following class:
public class Something
{
public SomeFlag = False;
public Something()
{
}
}
Somewhere in the system, we have composed a related list of objects into List.
Now, we want to scan through this list and extract into "List< bool> flags" all the flags (by reference?):
List<bool> flags = new List<bool>();
foreach (var stuff in List<Something>)
{
flags.Add(stuff.SomeFlag);
}
Finally, somewhere else, I want to update these flags, but the update should affect the original object:
public static void SetStates(List<bool> myList)
{
// The flag should get set to true by reference in the original object
myList.SomeFlag = True;
}
Using actions could be one way to achive this:
public class Something
{
public bool SomeFlag { get; set; }
}
internal class Program
{
private static void Main()
{
var somethings = new[] {new Something(), new Something()};
var flags = new List<Action<bool>>();
// create your list of 'pointers'
foreach (var something in somethings)
{
flags.Add(x => something.SomeFlag = x);
}
// set them all to true
foreach (var action in flags)
{
action(true);
}
// check the results
foreach (var something in somethings)
{
Console.WriteLine(something.SomeFlag);
}
Console.WriteLine("press any key to exit...");
Console.ReadLine();
}
}
In C#, you cannot save a reference to a property value (like a pointer to the memory location where the value is stored). You only can save a reference to an object which contains this property value.
In your var list = new List<Something>(), you can store those references to the objects.
Note that it's impossible for value types though. If Something is a struct, not a class, then the list will contain copies of the objects, not the references to the objects. So the rest of my answer assumes we're talking about class Something.
You can define a property changing behavior and apply it using the list of the objects.
If you already know at compile time which properties and which values do you need, you can create a lambda and pass it around.
// Define the behavior and get the object list
Action<Something> setter = o => o.Someflag = true;
var objectList = new List<Something>();
// Call your processing method later on
SetProperties(objectList, setter);
void SetProperties<T>(List<T> objects, Action<T> setter)
{
objects.ForEach(setter);
}
If you don't know at compile which properties and which values you will need, then things get much more complicated. You will need to use Reflection to obtain the property descriptors and to set the values.
Here is a simplified example:
// Define the behavior and get the object list
var objectList = new List<Something>();
string propertyName = "SomeFlag";
PropertyInfo pi = typeof(Something).GetProperty(propertyName);
MethodInfo setter = pi.GetSetMethod();
object value = true;
// Call your processing method later on
SetProperties(objectList, setter, value);
void SetProperties<T>(List<T> objects, MethodInfo setter, object value)
{
var arguments = new object[] { value } ;
objects.ForEach(o => setter.Invoke(o, arguments));
}

How can I traverse the list of a class A within a classA? [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 4 years ago.
Improve this question
I have a class called FilterType. Inside this class I have a list of a same class as a data member. I'm trying to loop though each and every member of the list and the list within the list. This is my code.
public class FilterType
{
string name;
int id;
string OR;// Either "OR" or AND only one condition is true.
string AND;//
List<FilterType> fl = new List<FilterType>();
}
I have started with something like this:
if(fl.count>0)
{
}
I'm not sure how to go through each and every member in this list. Let me know if any one has any suggestion.
Basically what you are looking for is recursive iteration. A lot of data structure (trees) would need similar functionality. You can do it using loops:
private static void Recurse(List<FilterType> fl)
{
foreach (var item in fl)
{
//do whatever you want with the current item, am just setting the name again
item.name = "Looped through";
//Go through the child list
Recurse(item.fl);
}
}
Or you can do it using the SelectMany linq operator (think of selectMany equivalent of a loop within loop), and then iterate over the flattendList doing what you want.
var flattendList= root.fl.SelectMany(f => f.fl);
Do be careful with the recursion, if your data is big then the code might not be performant and there are chances that it might throw out of memory exception.
What you need is loop, you can use any of the loop elements of the C# language:
foreach(var item in fl)
{
Console.WriteLine(item.GetType());
}
Or the for expression to iterate using indexes
for(var i = 0; i < fl.Count; I++)
{
Console.WriteLine(fl[i].GetType());
}
Hope this help!
PS: sorry for the editing, writing from my mobile
If you want to enumerate recursively, you can do it bu using yield return.
public IEnumerable<FilterType> EnumerateRecursively()
{
yield return this;
foreach (var item in fl)
{
foreach (var subItem in item.EnumerateRecursively())
{
yield return subItem;
}
}
}
C# make it relatively trivial to do that without intermediate accumulation and without having to write a lot of boilerplate code.
public enum LogicalOperator { OR, AND }
public class FilterType
{
public string name {get;set;}
public int id {get;set}
public LogicalOperator ConditionType {get;set;}
public List<FilterType> fl {get;private set;} = new List<FilterType>();
public IEnumerable<FilterType> Descendants {
get
{
foreach(var f in fl)
{
yield return f;
foreach(var child in f.Descendants)
{
yield return child;
}
}
}
}
}
I don't understand what exactly you wanna achieve
If you just want to loop the list fl, there are many ways to do it.
I would use foreach loop like this.
foreach (var item in fl)
{
// Do something with item.
}
and if you want to loop the list outside of the class.
Rather than setting the list to public.
It is recommended that you create a function inside the class that does something with a 'list' outside the class.
I mean, if you want to do something with the list lf like this outside of the class
if(FilterType.fl.Count > 0)
{
// Do something.
}
I would recommend that you create a function like this inside the class
public class FilterType
{
string name;
int id;
List<FilterType> fl = new List<FilterType>();
public bool IsEmpty()
{
return fl.Count > 0 ? false : true;
}
}
and use it outside of the class like this.
if(filterType.IsEmpty())
{
// Do something.
}
I hope this answer can help you.
Thank you.

How to change the below "ForEach loop" into simple IList<Record> or any other collection?

Foreach loop in my below code is taking more time for 50,00,000 Records.
Instead I need to change and assign it to a simple List or Ienumerable collection to find Distinct collection.
My question is how to convert the below ForEach loop into a List<Records> or any other collection (without using loop). I have added my coding structure. Please help me resolve. //Please refer the comments in CODE.
Class MainFilter
{
Private Void GetRecords()
{
List<object> choices = new List<Object>();
// Instead of the below line can I get the FilterItems implicitly converted.
// I need a collection without ForeachLoop...something like the below.
// List<Record> recordsCollection = table.FilterItems; Please help.
// Foreach loop is taking more time I need this to be converted to
// simple collection using IList or Enumerable
foreach (Record rec in table.FilterItems)
{
Choices.Add(rec.GetValue());
}
}
}
Public Class SecondTable: IContainerElement, IDisposable
{
public ThirdFilterItems FilterItems
{
get
{
_filteredRecords = new ThirdFilterItems(this);
}
}
}
public class ThirdFilterItems: FourthFilterItems
{
internal ThirdFilterItems(SecondTable table) : base(table)
{
}
}
public class FourthFilterItems: IList, IDisposable
{
public Record this[int index]
{
get
{
return record;
}
}
}
The following will give you a collection of "choices" without yet iterating over the collection.
table.FilterItems.Select(x => x.GetValue())
Is that what you're looking for? It's not a list. If you need to convert it to a list then you will have to iterate over the collection to do so.
You could do this, using Linq:
List<Record> recordsCollection = table.FilterItems
.Select(r => r.GetValue())
.ToList();
But don't expect it to be faster... internally, it still does the same thing as your original code. There's no way to solve this problem without a loop, or the moral equivalent of a loop.

How to update an entire object in a list C#?

I have a list of object and I want to replace one of the objects in the list with the new object:
public Parent AppendParentChildren(Request request)
{
var Children = request.Parent.Children.ToList();
if (Children.Any(x => x.TrackingNumber == request.Child.TrackingNumber))
{
//Here I want to replace any Children that have the same tracking number in the list with the new Child passed in
}
else
{
Children.Add(request.Child);
}
request.Parent.Children = Children;
return request.Parent;
}
public class Request
{
public Parent Parent { get; set; }
public Child Child { get; set; }
}
public class Parent
{
public IEnumerable<Child> Children {get;set;}
}
If I try and use it in a loop:
public static class Extension
{
public static void Update<T>(this List<T> items, T newItem)
{
foreach (var item in items)
{
//this
item = newItem;
}
}
}
item is read only, so I cannot replace the object in the list.
Any suggestions?
You can't change the member of a foreach iteration because foreach implements the IEnumerable type which is read-only.
A solution would be to cast the list of items inside the extension method as a List (which is read-writable). Then you'd want to identify which item(s) in the list you are replacing and update them. Below is what the Update extension method would look like (assuming you're in a situation where you can use LINQ)
public static class Extension
{
public static void Update<T>(this List<T> items, T newItem)
{
var childList = items as List<Child>;
var newChildItem = newItem as Child;
var matches = childList.Where(x => x.TrackingNumber == newChildItem.TrackingNumber).ToList();
matches.ForEach(x => childList[childList.IndexOf(x)] = newChildItem);
}
}
I've put a working example (albeit slightly bloated) on dotnetfiddle
https://dotnetfiddle.net/MJ5svP
It's also worth noting that although it looks like you're altering childList, this is actually referenced back to the original list not creating a copy (more info on this here)

How to create a method similar to ForEach

This is purely academic, but how would I create a method like the ForEach?
Say if I wanted to do something like the following:
SomeTenumerable.MyOwnFunction(x =>
{
x.Id = 0;
x.Order_Id = 0;
});
Note: I've only just got familiar with func<T,TResult>, so I'm not sure if it's the same thing.
Extra points if you can tell me the proper name/label of what I'm trying to achieve, I'm guessing it's some sort of delegate?
Demo here - https://dotnetfiddle.net/v7JKoo
.Each extension I use regularly - taken from http://extensionmethod.net/csharp/ienumerable-t/each-t
public static void Each<T>(this IEnumerable<T> items, Action<T> action)
{
if (items == null) return;
foreach (var item in items)
action(item);
}
Example:
var items = new List<Item>();
// populate items
items.Each(item => item.DoSomething());
Yes you are passing in a delegate (here it is an Action) to perform on each item
PS if you are looking to return items look at linqs .Where or .Select
I think what you want to do is create an extension method (MSDN)
ForEach is a method in the List class (you can see the code here). Since you cannot add a method to the class, you can create an extension method that lives in your project but can be used as it was part of the original List class.
Let's say your items use this interface
public interface IYourInterface
{
int Id;
int Order_Id;
}
You create a static method in a static class:
static class HelperMethods
{
public static void ResetAll(this List<IYourInterface> collection)
{
collection.ForEach(x =>
{
x.Id = 0;
x.Order_Id = 0;
});
}
}
And then use the method on any instance of List.
var collection = new List<IYourInterface>();
collection.ResetAll();
var otherStuff = new List<string>();
// This won't work because because List<string> cannot
// be converted to List<IYourInterface>
// otherStuff.ResetAll();
Add Property class
Public MyClass
{
public static int Id {get;set;}
public static int Order_Id{get;set;}
}
You can set it like this
IEnumerable<MyClass> myclass = new IEnumerable<MyClass>(
{
Id = 0;
Order_Id = 0;
});
You can query through, serach throw etc.
See this question, Here The question itself not the anwer.

Categories