How to find an object nested in multi-level collection - c#

Lets say I have a List<Family> and each Family has a List<Child>.
When I encounter a Child object in my code, how can I determine if the child is a part of any family?
Pseudo code:
If Child not in any family
// Do something with child
Update:
Example models:
class Family
{
public List<Child> Children {get;set;}
// Properties
}
class Child
{
// Properties
}
Example ViewModel:
class FamilyViewModel
{
public List<Family> Families {get;set;}
public bool ChildHasFamily(Child child)
{
// Determine if child is in any family or not
}
}

Now this isn't all that clean to me. I think your Child should have Family property to make things easier. If I understand correctly, your view model has a list of family which in turn contains a list of childs. When you receive a list of child, you want to know if it is in one of your family:
class FamilyViewModel
{
public List<Family> Families {get;set;}
public void ChildHasFamily(Child child)
{
var hasFamily = Families.SelectMany(f => f.Children)
.Contains(child);
}
}
Note that this will do an object reference comparison. If Child implement IEquatable<Child>, it will work out of the box. If not, you can use:
class FamilyViewModel
{
public List<Family> Families {get;set;}
public void ChildHasFamily(Child child)
{
var hasFamily = Families.SelectMany(f => f.Children)
.Any(c => c.Name == child.Name);
}
}
Replace the Where predicate for your identity comparison.

You could use following recursive Traverse method which uses deferred execution.
Then it's easy as:
IEnumerable<Family> familiesOfChild = families.Traverse(f => f.Children)
.Where(c => c.Equals(yourChild));
if(!familiesOfChild.Any())
{
// oh, what a poor child
}
Here is the extension method:
public static IEnumerable<T> Traverse<T>(this IEnumerable<T> source, Func<T, IEnumerable<T>> fnRecurse)
{
foreach (T item in source)
{
yield return item;
IEnumerable<T> seqRecurse = fnRecurse(item);
if (seqRecurse != null)
{
foreach (T itemRecurse in Traverse(seqRecurse, fnRecurse))
{
yield return itemRecurse;
}
}
}
}

Related

How to Cast List<T> to my own Collection

I have implemented my own collection class for various reasons.
How to avoid casting failure on ItemCollection resultCollection = (ItemCollection)list;? I'm inheriting from List<T> so shouldn't I be able to cast? Can I modify my BaseEntityCollection to become able to do this?
static class Program
{
static void Main()
{
ItemCollection collection = new ItemCollection();
Item item = new Item();
item.ID = 1;
item.Name = "John";
collection.Add(item);
List<Item> list = collection.FindAll(x => x.ID == 1 && x.Name == "John");
ItemCollection resultCollection = (ItemCollection)list; // It's breaking here
}
}
public class ItemCollection : BaseEntityCollection<Item>
{
}
public class Item : BaseEntity
{
public int ID { get; set; }
public string Name { get; set; }
}
public abstract class BaseEntityCollection<T> : List<T>, IEnumerable<T> where T : BaseEntity, new()
{
}
public abstract class BaseEntity
{
}
I know that I can implement FindAllseparately on my ItemCollection But I wanted to take advantage of all the methods available on List<T>.
Also I know that I can do list.ForEach(resultCollection.Add);. But that means iterating the collection all over again which I'd like to avoid.
Just change your constructors around so that you can initialize it with a List<Item> collection. This lets you initialize the item collection with another collection:
static class Program
{
static void Main()
{
ItemCollection collection = new ItemCollection();
Item item = new Item();
item.ID = 1;
item.Name = "John";
collection.Add(item);
List<Item> list = collection.FindAll(x => x.ID == 1 && x.Name == "John");
ItemCollection resultCollection = new ItemCollection(list);
}
}
public class ItemCollection : BaseEntityCollection<Item>
{
//Allow default constructor
public ItemCollection() { }
//Construct with a list collection
public ItemCollection(IEnumerable<Item> collection)
: base(collection)
{
}
}
public class Item : BaseEntity
{
public int ID { get; set; }
public string Name { get; set; }
}
public abstract class BaseEntityCollection<T> : List<T>, IEnumerable<T> where T : BaseEntity, new()
{
//Still be able to create blank items
public BaseEntityCollection() { }
public BaseEntityCollection(IEnumerable<T> collection)
: base(collection)
{
}
}
public abstract class BaseEntity
{
}
In order to avoid iterating your list twice, I would change the following:
List<Item> list = collection.FindAll(x => x.ID == 1 && x.Name == "John");
to
var list = collection.Where(x => x.ID == 1 && x.Name == "John");
Which will lazy-load your list (in a sorts), but it will only iterate your collection once, when you create the new ItemCollection from it.
To augment the already great answers. You asked:
I'm inheriting from List so shouldn't I be able to cast?
Yes and no.
Your particular cast works at compile time but not at runtime.
Casting is a way of telling the compiler, "Trust me. This will work at runtime."
At runtime, we can cast from a Base class to a Descendant class only when the underlying object inside of Base is actually an object of type Descendant.
For instance, keeping in mind that string descends from object, here is an illustration of why your cast fails at runtime.
// builds but fails at runtime
object o1 = new object();
string s1 = (string)o1;
// builds and works at runtime
// because o2 is a string in object's clothing
object o2 = (object)"";
string s2 = (string)o2;
ItemCollection resultCollection = new ItemCollection();
resultCollection.AddRange(collection.Where(x => x.ID == 1 && x.Name == "John"));
If by chance you don't have the AddRange extension method, make it.
void AddRange<T>(this ItemCollection c, IEnumerable<T> items) => foreach(T i in items) c.Add(i);

Simplest way to Recurse Over Object Tree

I have a base class:
public abstract class BaseClass{
public bool IsSelected {get; set;}
}
A derived class with a collection representing a hierarchy:
public class DerivedOne : BaseClass{
public ObservableCollection<BaseClass> Children {get; set;}
}
Another derived class:
public class DerivedTwo : BaseClass{
}
What is the simplest way to find all of the elements under a DerivedOne root that have IsSelected set to true?
You left out some requirement detail, but I think something like this should work:
public IEnumerable<BaseClass> AllIsSelected(BaseClass root)
{
if (root.IsSelected)
{
yield return root;
}
var composite = root as DerivedOne;
if (composite != null)
{
foreach (var v in composite.Children)
{
foreach (var x in AllIsSelected(v))
{
yield return x;
}
}
}
}
Of course, if you want a full list all at once, you could build the list instead of using 'yield'.
This is the same design discussed here: IEnumerable and Recursion using yield return.
As another answer said, you can use LINQ to shorten this somewhat. This version avoids making the temporary list.
public IEnumerable<BaseClass> AllIsSelected(BaseClass root)
{
if (root.IsSelected)
{
yield return root;
}
var composite = root as DerivedOne;
if (composite != null)
{
foreach (var x in composite.Children.SelectMany(v => AllIsSelected(v)))
{
yield return x;
}
}
}
The simplest method would be to use LINQ with recursion
public IEnumerable<BaseClass> GetAllSelectedChildren(DerivedOne derivedOne)
{
return derivedOne.Children.SelectMany(GetAllSelected);
}
public IEnumerable<BaseClass> GetAllSelected(BaseClass baseClass)
{
var selected = new List<BaseClass>();
if(baseClass.IsSelected)
{
selected.Add(baseClass);
}
var derivedOne = baseClass as DerivedOne;
if(derivedOne != null)
{
selected.AddRange(GetAllSelectedChildren(derivedOne));
}
return selected;
}
Use simple Linq.
return root.Children
.SelectMany(c => new[]{ c }.Concat(c.Children)) // flatten the structure including self node.
.Where(e => e.IsSelected) // filter selected items
.ToList();

Get element of known type in a list

I'm got a problem with derivative classes.
I have a parent class and several child classes
public abstract class Parent
{}
public class Child1 : Parent
{}
public class Child2 : Parent
{}
public class Child3 : Parent
{}
Then I have a list of those objects
List<Parent> myList = new List<Parent>(){ new Child1(), new Child2(), new Child2() .....};
I want a function to retrieve an object of this list specifying its type. For now, I build such methods one for each child type, but when the number of children types increase, it could be a problem
public Child1 GetChild1()
{
Child1 child = myList.FirstOrDefault(ch => ch is Child1) as Child1;
if(child == null)
{
child = new Child1;
myList.Add(child);
}
return child;
}
I'm looking for something like
public Parent GetChild(Type typeOfChild)
-- or --
public Parent GetChild(string typeOfChild)
-- or --
public Parent GetChild<T>()
EDIT: First progress
private void GetChild<T>() where T : class
{
IEnumerable<T> list = myList.OfType<T>();
T item;
if(list.Count() > 0)
{
item= list.First<T>();
}
else
{
item= Activator.CreateInstance<T>();
}
myList.Add(workspace); //invalid argument
}
EDIT : Solution
private void GetChild<T>() where T : Parent, new()
{
T item = myList.FirstOrDefault(ch => ch is T) as T;
if(item == null)
{
item = new T();
myList.Add(item);
}
OtherMethod(item);
}
you can use myList.OfType<Child1>()
OfType<T> filters the elements of an IEnumerable based on a specified type.
Read more...
To give a cleaner solution thanks to Alexei
private void GetChild<T>() where T : Parent, new()
{
T item = myList.FirstOrDefault(ch => ch is T) as T;
if(item == null)
{
item = new T();
myList.Add(item);
}
OtherMethod(item);
}

C# iterate on class own elements

I have created a class which inherits from List: Now I want to iterate the elements of the class in the class itself and return the object if it satisfies certain criteria (e.g. its Property name):
protected class myList : List<Object>
{
getElement(string name)
{
??? LOOP AND IF CONDITION ???
return element;
}
}
Can you help? Thanks
You're looking for foreach(var item in this).
First, I would try to avoid using List<Object>.The problem with Object is, that it needs casting. Hence it is prone to errors at runtime.
Rather create your own class.
For example, a simple item, which holds a name.
class Item
{
public string Name { get; set; }
}
Then you can simply do:
class myList : List<Item>
{
Item getItem(string name)
{
foreach(var item in this)
{
if(item.Name==name) { return item; }
}
return null;
}
}
You'd want some more code for the casting, but:
public Object GetElement(string name)
{
Object element = null;
foreach (var item in this)
{
if (item.ToString() == name)
{
element = item;
break;
}
}
return element;
}
You don't have to reinvent the wheel, just use LINQ.
mylist.First(element => /*criteria*/);

How to expose read-only collection another type of private collection?

Here is my problem: there is a class that contains a inner collection (or list, or array, or something like this) of some some class and It must expose a public read-only collection of items, which are properties (or fields) of relative items in inner collection. For example:
//Inner collection consists of items of this class
class SomeClass
{
public int _age;
//This property is needed for exposing
public string Age { get { return this._age.ToString(); } }
}
//Keeps inner collection and expose outer read-only collection
class AnotherClass
{
private List<SomeClass> _innerList = new List<SomeClass> ();
public ReadOnlyCollection<string> Ages
{
get
{
//How to implement what i need?
}
}
}
I know a simple way to do this by the use of a pair of inner lists, where the second keeps values of needed properties of first. Something like this:
//Inner collection consists of items of this class
class SomeClass
{
public int _age;
//This property is needed for exposing
public string Age { get { return this._age.ToString(); } }
}
//Keeps inner collection and expose outer read-only collection
class AnotherClass
{
private List<SomeClass> _innerList = new List<SomeClass> ();
private List<string> _innerAgesList = new List<string> ();
public ReadOnlyCollection<string> Ages
{
get
{
return this._innerAgesList.AsreadOnly();
}
}
}
But I dislike this overhead. May be there is some way to do what I want with exposing interfaces. Help me, please!
Hurra!
It seems that the best solution has been found. Due to the post of Groo
this problem found its almost universal answer. Here is It (we need to add two entity):
public interface IIndexable<T> : IEnumerable<T>
{
T this[int index] { get; }
int Count { get; }
}
class Indexer <Tsource, Ttarget> : IIndexable<Ttarget>
{
private IList<Tsource> _source = null;
private Func<Tsource, Ttarget> _func = null;
public Indexer(IList<Tsource> list, Func<Tsource, Ttarget> projection)
{
this._source = list;
this._func = projection;
}
public Ttarget this[int index] { get { return this._func(this._source[index]); } }
public int Count { get { return _source.Count; } }
IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); }
public IEnumerator<Ttarget> GetEnumerator()
{ foreach (Tsource src in this._source) yield return this._func(src); }
}
With them, our implementation looks like this:
//Inner collection consists of items of this class
class SomeClass
{
public int _age;
//This property is needed for exposing
public string Age { get { return this._age.ToString(); } }
}
//Keeps inner collection and expose outer read-only collection
class AnotherClass
{
private List<SomeClass> _innerList = new List<SomeClass> ();
private Indexer<SomeClass, string> _indexer = null;
public AnotherClass ()
{ this._indexer = new Indexer<SomeClass, string > (this._innerList, s => s.Age); }
public IIndexable<string> Ages { get { return this._indexer; } }
}
Thank Groo and the rest who answered. Hope, this helps someone else.
The overhead is not so significant if you consider that ReadOnlyCollection is a wrapper around the list (i.e. it doesn't create a copy of all the items).
In other words, if your class looked like this:
class AnotherClass
{
private ReadOnlyCollection<string> _readonlyList;
public ReadOnlyCollection<string> ReadonlyList
{
get { return _readonlyList; }
}
private List<string> _list;
public List<string> List
{
get { return _list; }
}
public AnotherClass()
{
_list = new List<string>();
_readonlyList = new ReadOnlyCollection<string>(_list);
}
}
Then any change to the List property is reflected in the ReadOnlyList property:
class Program
{
static void Main(string[] args)
{
AnotherClass c = new AnotherClass();
c.List.Add("aaa");
Console.WriteLine(c.ReadonlyList[0]); // prints "aaa"
c.List.Add("bbb");
Console.WriteLine(c.ReadonlyList[1]); // prints "bbb"
Console.Read();
}
}
You may have issues with thread safety, but exposing IEnumerable is even worse for that matter.
Personally, I use a custom IIndexable<T> interface with several handy wrapper classes and extension method that I use all over my code for immutable lists. It allows random access to list elements, and does not expose any methods for modification:
public interface IIndexable<T> : IEnumerable<T>
{
T this[int index] { get; }
int Length { get; }
}
It also allows neat LINQ-like extension methods like Skip, Take and similar, which have better performance compared to LINQ due to the indexing capability.
In that case, you can implement a projection like this:
public class ProjectionIndexable<Tsrc, Ttarget> : IIndexable<Ttarget>
{
public ProjectionIndexable
(IIndexable<Tsrc> src, Func<Tsrc, Ttarget> projection)
{
_src = src;
_projection = projection;
}
#region IIndexable<Ttarget> Members
public Ttarget this[int index]
{
get { return _projection(_src[index]); }
}
public int Length
{
get { return _src.Length; }
}
#endregion
#region IEnumerable<Ttarget> Members
// create your own enumerator here
#endregion
}
And use it like this:
class AnotherClass
{
private IIndexable<string> _readonlyList;
public IIndexable<string> ReadonlyList
{
get { return _readonlyList; }
}
private List<SomeClass> _list;
public List<SomeClass> List
{
get { return _list; }
}
public AnotherClass()
{
_list = new List<SomeClass>();
_readonlyList = new ProjectionIndexable<SomeClass, string>
(_list.AsIndexable(), c => c.Age);
}
}
[Edit]
In the meantime, I posted an article describing such a collection on CodeProject. I saw you've implemented it yourself already, but you can check it out nevertheless and reuse parts of the code where you see fit.
Why don't you just return IEnumerable?
If you have access to LINQ (.NET 3.5) then just use a select()
public IEnumerable<string> Ages{
get{
return _innerList.Select(s => s.stringProperty);
}
}
in this case I normaly just use IEnumerable - if the collection is readonly and you don't need the Index-functionality you can just do somehting like this:
public IEnumerable<string> Ages
{
get
{
return this._innerList.Select(someObj => someObj.Age).ToArray();
}
}

Categories

Resources