Nested List — Get list item of parent list - c#

i want to write a C# function which returns "alamaba" when i pass "Montgomery".
2nd example: Sitka --> Alaska
here is the list of the example:
List<PopulationUSA> result = new List<PopulationUSA>();
PopulationUSA usa = new PopulationUSA("Population in USA", 316128839, new List<PopulationUSA>());
result.Add(usa);
PopulationUSA alabama = new PopulationUSA("Alabama", 4833722, new List<PopulationUSA>());
usa.Items.Add(alabama);
alabama.Items.Add(new PopulationUSA("Birmingham", 212113, null));
alabama.Items.Add(new PopulationUSA("Montgomery", 201332, null));
alabama.Items.Add(new PopulationUSA("Mobile", 194899, null));
PopulationUSA alaska = new PopulationUSA("Alaska", 735132, new List<PopulationUSA>());
usa.Items.Add(alaska);
alaska.Items.Add(new PopulationUSA("Juneau", 32660, null));
alaska.Items.Add(new PopulationUSA("Ketchikan", 8214, null));
alaska.Items.Add(new PopulationUSA("Sitka", 9020, null));
here is the class:
public class PopulationUSA
{
public PopulationUSA(string name, int value, List<PopulationUSA> items)
{
Name = name;
Value = value;
Items = items;
}
public string Name { get; set; }
public int Value { get; set; }
public List<PopulationUSA> Items { get; set; }
}
How can i do that?
Thanks

you can add this method to the PopulationUSA class
public string FindParentsOfGrandChildren(string _name)
{
List<PopulationUSA> parents = Items.Where(s => s.Items.Any(c => c.Name == _name)).ToList();
if (parents != null)
{
string listparents = string.Empty;
for (int i = 0; i < parents.Count; i++)
{
if (i == 0)
{
listparents += parents[i].Name;
}
else
{
listparents += ", " + parents[i].Name;
}
}
return listparents;
}
else
{
return "Not found";
}
}
then use it like this in your example:
string WhereDoIBelong = usa.FindParentsOfGrandChildren("Montgomery")
it would be much better as a recursive method, finding parents of any type (not just "grandchildren") but that is your work!

Related

Search a hierarchy of class and return the path to get there

I have this class, a hierarchy of categories.
class Categories
{
public long Id { get; set; }
public long ParentId { get; set; }
public string Name { get; set; }
public bool IsActive { get; set; }
public List<Categories> ChildrenData { get; set; }
}
How can I recursively iterate through this class of unknown depth and return the path to get there?
All "Id" values are unique. Say I want to find Id = 23 and get the path to get there by concatenating "Name".
For example, in the image below searching for ID = 23 would return: Default Category/Books/Nonfiction/Best-sellers
Example Hierarchy
My suggestion is that you first build an index:
public static Dictionary<long, Category> IndexBuilder(Category c)
{
var index = new Dictionary<long, Category>();
IndexBuilder(c, index);
return index;
}
private static void IndexBuilder(Category c, Dictionary<long, Category> index)
{
if (index.ContainsKey(c.Id))
return;
index[c.Id] = c;
foreach(var child in c.ChildrenData)
IndexBuilder(child, index);
}
Now you have a lookup, and your path is then easy to produce:
static IEnumerable<Category> PathToRoot(long id, Dictionary<long, Category> index)
{
// Presumably the parent id of the top category is a sentinel.
long current = id
while (current != 0)
{
var category = index[current];
yield return category;
current = category.ParentId;
}
}
Or maybe we just go until we run out of index:
static IEnumerable<Category> PathToRoot(long id, Dictionary<long, Category> index)
{
long current = id
while (index.ContainsKey(current))
{
var category = index[current];
yield return category;
current = category.ParentId;
}
}
Now you have a tool you can use to make your string:
static string Slash<T>(this IEnumerable<T> items) =>
string.Join("/", items);
var s = PathToRoot(23, index)
.Reverse()
.Select(c => c.Name)
.Slash();
See what I am doing here? Make a bunch of helper methods each of which is about five lines long, that can be composed together to make powerful solutions.
I have provided 2 ways, the first way is recursive and the last is not.
Recursive way, add a reference to your parent. This way when you find a match you can easily traverse your way back up the chain to create your path.
class Categories
{
public Categories Parent { get; set; }
public long Id { get; set; }
public long ParentId { get; set; }
public string Name { get; set; }
public bool IsActive { get; set; }
public List<Categories> ChildrenData { get; set; }
}
Then add a Find() method:
public string Find(long id)
{
if( Id == id )
{
return GetPath(); //<-- we need to code this next.
}
else
{
foreach( var entry in Categories)
{
string path = entry.Find(id);
if( path != null )
{
return path;
}
}
return null;
}
}
And finally the GetPath(), the assumption here is that the highest level instances of Categories do not have a Parent:
public string GetPath()
{
System.Text.StringBuilder sb = new StringBuilder();
Categories current = this;
while( current != null)
{
sb.Insert(0,current.Name);
if( current != this)
{
sb.Insert(0,"/");
}
current = Parent;
}
return sb.ToString();
}
Now if recursion isn't what you want, then pass in the current path to the Find() method.
public string Find(long id, string pathSoFar)
{
if (pathSoFar == null)
{
pathSoFar = Name;
}
else
{
pathSoFar = pathSoFar + Name;
}
if ( Id == id)
{
return pathSoFar;
}
else
{
foreach( var entry in Categories)
{
string path = entry.Find(id, pathSoFar + "/");
if( path != null )
{
return path;
}
}
return null;
}
}
Usage:
var nonRecusive = cats.Find(23, null);
This will get what you are looking for using recursion:
void Main()
{
var data = GetData();
Console.WriteLine(GetPath(data, 23, ""));
}
public String GetPath(Categories c, Int32 id, String path)
{
if (c.Id == id)
{
return path + "/" + c.Name;
}
foreach (var cd in c.ChildrenData)
{
var p = GetPath(cd, id, path + "/" + c.Name);
if (!String.IsNullOrWhiteSpace(p))
{
return p;
}
}
return "";
}
public class Categories
{
public long Id { get; set; }
public long ParentId { get; set; }
public string Name { get; set; }
public bool IsActive { get; set; }
public List<Categories> ChildrenData { get; set; }
}
public Categories GetData()
{
return
new Categories
{
Id = 1,
Name = "Default Category",
ChildrenData = new List<Categories>
{
new Categories
{
Id = 2,
Name = "Magazines",
ChildrenData = new List<Categories> {}
},
new Categories
{
Id = 2,
Name = "Books",
ChildrenData = new List<Categories>
{
new Categories
{
Id = 20,
Name = "Fiction",
ChildrenData = new List<Categories> {}
},
new Categories
{
Id = 21,
Name = "Nonfiction",
ChildrenData = new List<Categories>
{
new Categories
{
Id = 22,
Name = "New",
ChildrenData = new List<Categories> {}
},
new Categories
{
Id = 23,
Name = "Best-Sellers",
ChildrenData = new List<Categories> {}
},
}
}
}
}
}
};
}

How can i create a class with a property for each country and it's items?

In the top of the class
public class Country
{
public string country { get; set; }
}
And how i build the links
public void ImagesLinks()
{
try
{
int counter = 0;
int cnt = 0;
foreach (string countryCode in countriescodes)
{
imagesUrls.Add(countriesnames[counter]);
counter++;
cnt++;
for (; cnt < DatesAndTimes.Count(); cnt++)
{
string imageUrlIrTrue = firstUrlPart + countryCode + secondUrlPart + DatesAndTimes[cnt] + thirdUrlPart + "true";
string imageUrlIrFalse = firstUrlPart + countryCode + secondUrlPart + DatesAndTimes[cnt] + thirdUrlPart + "false";
imagesUrls.Add(imageUrlIrTrue);
imagesUrls.Add(imageUrlIrFalse);
if (cnt % 10 == 0)
break;
}
}
}
catch(Exception err)
{
string myerr = err.ToString();
}
}
What i have in the end is a List with names and the links of each name.
For example in the index 0 i have the name: Europe
Then then ext 18 indexs are links of Europe
Then the next name is in index 21: Alps
And then the next 18 indxs of Alps
What i want to do is using the class Country is when i will type for example:
Country. ( After the point i will have properties of all the names Europe ,Alps and so on so i can select one of the names ) Same like if i will type for example File. so after the point i will have properties like Create Copy and so on so when i will type Country i will have all the countries names Europe, Alps....
And then if i will make a loop over one of the names it will loop over it's 18 items. For example:
For (int i = 0; i < Country.Europe; i++)
{
// something to do with Country.Europe[i]
}
Or
For (int i = 0; i < Country.Alps; i++)
{
// something to do with Country.Alps[i]
}
So maybe each name/country should be a List of it self ?
For (int i = 0; i < Country.Europe.Count(); i++)
{
// something to do with Country.Europe[i]
}
But the idea is that i will be able easy to select a name from a properties list and when loop over the name it will loop over it's 18 items.
I threw this together real fast - it is how I would probably handle it. I added a little more, I think you just need a class to handle countries. In any case, you would need to adjust your loop to create this structure, so this isn't a perfect solution - but it's how I would do it. You could also use linq instead of loops, I did this more as a class-based answer than a "pretty" answer.
namespace classTest
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
World newWorld = new World();
Continent Europe = new Continent();
Europe.name = "Europe";
Country England = new Country();
England.name = "England";
List<string> imageUrl = new List<string>();
imageUrl.Add("url1-England");
imageUrl.Add("url2-England");
imageUrl.Add("url3-England");
England.imageUrls = imageUrl;
Europe.countries.Add(England);
newWorld.continents.Add(Europe);
Country France = new Country();
France.name = "France";
imageUrl = new List<string>();
imageUrl.Add("url1-France");
imageUrl.Add("url2-France");
imageUrl.Add("url3-France");
France.imageUrls = imageUrl;
Europe.countries.Add(France);
foreach (Continent continent in newWorld.continents)
{
Console.WriteLine(continent.name);
foreach (Country country in continent.countries)
{
Console.WriteLine(country.name);
foreach(string imageUri in country.imageUrls)
{
Console.WriteLine(imageUri);
}
}
}
}
}
public class World
{
public List<Continent> continents;
public World()
{
continents = new List<Continent>();
}
}
public class Continent
{
public string name;
public List<Country> countries { get; set; }
public Continent()
{
name = string.Empty;
countries = new List<Country>();
}
}
public class Country
{
public string name { get; set; }
public List<string> imageUrls { get; set; }
public Country()
{
name = string.Empty;
imageUrls = new List<string>();
}
}
}
In the following solution, I use an outer wrapper Country that provides static references to instances for the continents (e.g. Europe). The continents implement IEnumerable, so you can iterate over all countries of this continent or use LINQ to filter them.
public class CountryData : IEquatable<CountryData>{
public string Link { get; set; }
public bool Equals(CountryData other) {
if (other == null) {
return false;
}
return StringComparer.Ordinal.Equals(Link, other.Link);
}
public override int GetHashCode() {
return Link.GetHashCode();
}
}
public static class Country {
public static readonly Europe Europe = new Europe();
}
public class Europe : IEnumerable<CountryData> {
private List<CountryData> All => new List<CountryData> {
Austria,
Belgium
};
public CountryData Austria = new CountryData { Link = #"\Country\Austria" };
public CountryData Belgium = new CountryData { Link = #"\Country\Belgium" };
IEnumerator<CountryData> IEnumerable<CountryData>.GetEnumerator() {
return All.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator() {
return All.GetEnumerator();
}
}
Usage examples:
var austria = Country.Europe.Austria;
var belgium = Country.Europe.Single(c => c.Link.Contains("Belgium"));
foreach (var european in Country.Europe) {
Console.WriteLine(european.Link);
}
Edit
If you want to compare countries, CountryData must implement IEquatable<CountryData>
Usage example:
var isSame = Country.Europe.Austria == Country.Europe.Belgium;
// isSame is false

Create distinct expando object list

I have created a method which will create dynamic object list from an object list according to property list. In this case I have completed such task using Expandoobject. But I have failed to create distinct list of such expando object list. Please visit the following fidder and see my code.
public class Program
{
public static void Main()
{
var _dynamicObjectList = new List<Student>();
for (int i = 0; i < 5; i++)
{
_dynamicObjectList.Add(new Student { ID = i, Name = "stu" + i, Address = "address" + i, AdmissionDate = DateTime.Now.AddDays(i) , Age=15, FatherName="Jamal"+i, MotherName = "Jamila"+i});
}
//create again for checking distinct list
for (int i = 0; i < 5; i++)
{
_dynamicObjectList.Add(new Student { ID = i, Name = "stu" + i, Address = "address" + i, AdmissionDate = DateTime.Now.AddDays(i), Age = 15, FatherName = "Jamal" + i, MotherName = "Jamila" + i });
}
// var returnList = test2.GetDdlData<Object>(_dynamicObjectList, "ID,Name,Address");
// var returnList = test2.GetDdlData<Object>(_dynamicObjectList, "ID,FatherName,Address");
var returnList = test2.GetDdlData<Object>(_dynamicObjectList, "ID,Name,FatherName,MotherName,Age");
string strSerializeData = JsonConvert.SerializeObject(returnList);
Console.WriteLine(strSerializeData);
Console.ReadLine();
}
}
public class Student
{
public int? ID { get; set; }
public string Name { get; set; }
public string Address { get; set; }
public DateTime AdmissionDate { get; set; }
public string FatherName { get; set; }
public string MotherName { get; set; }
public int Age { get; set; }
}
public static class test2
{
public static IList GetDdlData<T>(this IEnumerable<T> source, string userParams)
{
try
{
List<string> otherProperties = userParams.Split(',').ToList();
Dictionary<string, PropertyInfo> parentPropertyInfo = new Dictionary<string, PropertyInfo>();
Dictionary<string, Type> parentType = new Dictionary<string, Type>();
var dynamicObjectList = (from k in source select k).ToList();
if (dynamicObjectList.Count() > 0)
{
//if parentField exists then system will handle parent property
if (otherProperties.Count > 0)
{
foreach (string otherProperty in otherProperties)
{
//get parent field property info
PropertyInfo _info = dynamicObjectList[0].GetType().GetProperty(otherProperty);
parentPropertyInfo.Add(otherProperty, _info);
//get parent field propertyType
Type pType = Nullable.GetUnderlyingType(_info.PropertyType) ?? _info.PropertyType;
parentType.Add(otherProperty, pType);
}
}
}
//return List
IList<object> objList = new List<object>();
foreach (T obj in source)
{
var dynamicObj = new ExpandoObject() as IDictionary<string, Object>;
foreach (string otherProperty in otherProperties)
{
PropertyInfo objPropertyInfo = parentPropertyInfo.FirstOrDefault(m => m.Key == otherProperty).Value;
Type objPropertyType = parentType.FirstOrDefault(m => m.Key == otherProperty).Value;
Object data = (objPropertyInfo.GetValue(obj, null) == null) ? null : Convert.ChangeType(objPropertyInfo.GetValue(obj, null), objPropertyType, null);
dynamicObj.Add(otherProperty, data);
}
objList.Add(dynamicObj);
}
var returnUniqList = objList.Distinct().ToList();
return returnUniqList;
}
catch (Exception ex)
{
throw ex;
}
}
}
https://dotnetfiddle.net/hCuJwD
Just add the following code in the code block.
foreach(var objTemp in objList) {
bool isNotSimilar = true;
foreach(string property in otherProperties) {
//get sending object property data
object tempFValue = (objTemp as IDictionary < string, Object > )[property];
//get current object property data
object tempCValue = (dynamicObj as IDictionary < string, Object > )[property];
if (!tempFValue.Equals(tempCValue)) {
isNotSimilar = false;
break;
}
}
if (isNotSimilar) {
isDuplicate = true;
break;
}
}
DOTNETFIDDLE

C# - How to search into the ObservableCollection?

I am developing a app in windows phone 7. I have a list box with items of observable collection. Now i want to search into that list box items. I want filter the items which is typed in the Text Box. If i type 'a' mean the list box items should shows the items which is start with 'a'. If i type 'az' mean it should show the items start with 'az'.
public class SortingExampleViewModel : ReactiveObject
{
public string _SearchText = "";
public string SearchText
{
get { return _SearchText; }
set { this.RaiseAndSetIfChanged(x => x.SearchText, value); }
}
public static ObservableCollection<items> _sordtedList;
public ObservableCollection<items> sordtedList
{
get { return _sordtedList; }
set { this.RaiseAndSetIfChanged(x => x.sordtedList, value); }
}
public static ObservableCollection<items> _tempSordtedList;
public ObservableCollection<items> tempSordtedList
{
get { return _tempSordtedList; }
set { this.RaiseAndSetIfChanged(x => x.tempSordtedList, value); }
}
public ReactiveAsyncCommand ExecuteSearch { get; set; }
public SortingExampleViewModel()
{
ObservableCollection<items> myData = new ObservableCollection<items>()
{
new items(){firstName = "Vijay Dhas",age=27},
new items(){firstName = "Ramaraj",age=28},
new items(){firstName = "Arun",age=29},
new items(){firstName = "Prabhu",age=30},
new items(){firstName = "Pranesh",age=31},
new items(){firstName = "Testing",age=32}
};
sordtedList = new ObservableCollection<items>(from i in myData orderby i.firstName select i);
var canConfirm = this.WhenAny(x => x.SearchText, (search) => SearchMethod(search.Value));
ExecuteSearch = new ReactiveAsyncCommand(canConfirm, 0);
}
public Boolean SearchMethod(String searchValue)
{
var col = (ObservableCollection<items>)(sordtedList.Where(p => p.firstName.Contains(searchValue)));
foreach (items objTest in col)
{
tempSordtedList.Add(objTest);
}
sordtedList = tempSordtedList;
return true;
}
}
public class items
{
public string firstName { get; set; }
public int age { get; set; }
}
But here i am getting Error in this line:
var col = (ObservableCollection<items>)(sordtedList.Where(p => p.firstName.Contains(searchValue)));
It showing Unknown error.
Please help me to search in the listbox.
I got the solution.
public SortingExampleViewModel()
{
ObservableCollection<items> myData = new ObservableCollection<items>()
{
new items(){firstName = "Vijay Dhas",age=27},
new items(){firstName = "Ramaraj",age=28},
new items(){firstName = "Arun",age=29},
new items(){firstName = "Prabhu",age=30},
new items(){firstName = "Pranesh",age=31},
new items(){firstName = "Testing",age=32}
};
sordtedList = new ObservableCollection<items>(from i in myData orderby i.firstName select i);
temp = sordtedList;
var canConfirm = this.WhenAny(x => x.SearchText, (search) => SearchMethod(search.Value));
ExecuteSearch = new ReactiveAsyncCommand(canConfirm, 0);
}
public Boolean SearchMethod(String searchValue)
{
ObservableCollection<items> tempList = new ObservableCollection<items>();
tempList = temp;
tempSordtedList = new ObservableCollection<items>();
foreach (items items in tempList)
{
if (items.firstName.ToLower().StartsWith(searchValue.ToLower()))
{
tempSordtedList.Add(items);
}
}
sordtedList = tempSordtedList;
return true;
}
You are casting an IEnumerable (result of the Linq query) to an ObservableCollection.
Use this instead:
var col = sordtedList.Where(p => p.firstName.Contains(searchValue));
Since you only use the variable col to iterate over it, you do not need to cast it.

Get the Depth of an object tree of objects with the same type using LAMBDA expression

I have this object:
public class dtHeader
{
public dtHeader ParentHeader { get; set; }
public string HeaderText { get; set; }
public string DataField { get; set; }
public bool Visible { get; set; }
public int DisplayOrder { get; set; }
}
I want to calculate using a lambda expression, the depth of the object, how many layers of the object in itself exists?
I saw this JavaScript post, but I am struggling to translate it to a one line lambda statement.
Lets say the object is as this new dtHeader(){ ParentHeader = null, HeaderText = "col1" };
the result would be 1
and for new dtHeader(){ ParentHeader = new dtHeader(){ ParentHeader = null, HeaderText = "col1" }, HeaderText = "col1" }; the result would be 2
I want to achieve this with a list<dtHeader>, so some of them would have a depth of 1 and others with deeper depths, and want the deepest depth.
_______ITEM_IN_LIST_OBJECT__
______1___2___3___4___5___6_
D 1. |_o_|_o_|_o_|_o_|_o_|_o_|
E 2. |_o_|___|_o_|___|_o_|_o_|
P 3. |___|___|_o_|___|_o_|___|
T 4. |___|___|___|___|_o_|___|
H 5. |___|___|___|___|_o_|___|
It must go infinitly(Until where it allows for objects to heap up inside eachother) deep.
var HeaderLayerCount = lDtCol.Where(n => n.ParentHeader != null)
.Where(n => n.ParentHeader.ParentHeader != null)
.Where(n => n.ParentHeader.ParentHeader.ParentHeader != null);
EDIT:
I just want to add that if you want to work on a specific depth level, for instance, all objects on a depth of 3, you can use this extra recursion function in the class
public class dtCol
{
public dtCol ParentHeader { get; set; }
public string HeaderText { get; set; }
public string DataField { get; set; }
public bool Visible { get; set; }
public int DisplayOrder { get; set; }
public int Depth { get { return ParentHeader != null ? ParentHeader.Depth + 1 : 1; } }
public int CurrentDepth { get; set; } //Set on initialisation
public dtCol getParent(dtCol col, int getDepth) //Gets the parent on a specific level after the first base level (1) else returns the previous not null child
{
return (col.ParentHeader != null && col.ParentHeader.CurrentDepth == getDepth) ? col.ParentHeader : this.getParent(col.ParentHeader, getDepth);
}
}
You can use it like so:
var HeaderLayerCount = lDtCol.OrderByDescending(n => n.Depth).First().Depth;
for (int hlc = 1; hlc <= HeaderLayerCount; hlc++)
{
var headerrow = new List<dtCol>();
//This foreach adds the parent header if not null else adds the not null child
lDtCol.ForEach(n =>
{
var h = n.getParent(n, hlc); //Get Parent, null is returned if parent does not exists
headerrow.Add((h != null) ? h : n); //If parent is null, add base dtCol so that the headers can be merged upwards.
});
//Do what you need with your new single dimensional list of objects
}
Why not implementing a int GetDepth() method on your class, that will reach the top most ancestor, counting each level?
Your query would then be much simpler.
I was outrunned by Frode, kudos to him
I had the same implementation:
public int GetDepth()
{
if (ParentHeader == null)
{
return 1;
}
else return 1 + ParentHeader.GetDepth();
}
using System;
using System.Linq;
namespace ConsoleApplication3
{
public class dtHeader
{
public dtHeader ParentHeader { get; set; }
public string HeaderText { get; set; }
public string DataField { get; set; }
public bool Visible { get; set; }
public int DisplayOrder { get; set; }
public int Depth
{
get
{
// If header has parent, then this depth is parent.depth + 1
if (ParentHeader != null)
return ParentHeader.Depth+1;
else
return 1; // No parent, root is depth 1
}
}
}
class Program
{
static void Main(string[] args)
{
dtHeader[] headers = {
new dtHeader { HeaderText = "dt1" },
new dtHeader { HeaderText = "dt2" },
new dtHeader { HeaderText = "dt3" },
new dtHeader { HeaderText = "dt4" },
new dtHeader { HeaderText = "dt5" }
};
headers[1].ParentHeader = headers[0];
headers[2].ParentHeader = headers[1];
headers[3].ParentHeader = headers[2];
headers[4].ParentHeader = headers[3];
var deepest = headers.OrderByDescending(item=>item.Depth).First();
Console.WriteLine(deepest.Depth+ ", " + deepest.HeaderText);
var runner = deepest;
while (runner.ParentHeader != null)
runner = runner.ParentHeader;
Console.WriteLine("The deepest root header is:" + runner.HeaderText);
}
}
}
Here's a lambda expression to get what you want:
Func<dtHeader, int> getDepth = null;
getDepth = dth =>
{
var depth = 1;
if (dth.ParentHeader != null)
{
depth += getDepth(dth.ParentHeader);
}
return depth;
};
You have to define it in two parts (assigning null & assigning the body) to let recursion work.
I modified Enigmativity's answer to make it work correctly:
Func<dtHeader, int, int> getDepth = null;
getDepth = (dth, depth) =>
{
if (dth.ParentHeader != null)
{
depth = getDepth(dth.ParentHeader, ++depth);
}
return depth;
};
Call it like this:
int depth = getDepth(header, 0)

Categories

Resources