Find a circular dependency in a collection c# - c#

I've a collection of DataItem class.
DataItem : Property RefItem stores ref to a DataItem that could be same collection.
public class DataItem
{
public int ID { get; set; }
public string Name { get; set; }
public DataItem RefItem { get; set; }
}
Collection:
private List<DataItem> dataitems;
public List<DataItem> DataItems
{
get { return dataitems; }
set { dataitems = value; }
}
Now I have two methods for adding data in the collection and validating data in collection.
public void AddItem(DataItem item)
{
DataItems.Add(item);
}
public bool ValidateDataItems()
{
//Logic for circular reference
//
return true;
}
I want a algorithm in validate method to check if there is any circular dependency in my collection.For ex. Below is an invalid data for me. As item3 is again pointed by item1.
var item1 = new DataItem() {ID=1,Name="First Item",RefItem =null};
var item2 = new DataItem() { ID = 1, Name = "First Item", RefItem = item1 };
var item3 = new DataItem() { ID = 1, Name = "First Item", RefItem = item2 };
item1.RefItem = item3;
AddItem(item1);
AddItem(item2);
AddItem(item3);
If items are added to collection like Item1->item2,item2-> item3,item3->item1 or any other possible combination of where a ref item of a class is pointing back. I want validation method to return false.
It's a circular dependency problem but I couldn't find any concrete algorithm to do so in c#.

Try something like this solution:
public class DataItem
{
public int ID { get; set; }
public string Name { get; set; }
public DataItem RefItem { get; set; }
}
public class Checker
{
public static bool Check(DataItem item)
{
var chain = new Dictionary<DataItem, DataItem>();
chain.Add(item, null);
try
{
ProcessNodes(chain, item);
return true;
}
catch (ArgumentException)
{
return false;
}
}
private static void ProcessNodes(Dictionary<DataItem, DataItem> chain, DataItem item)
{
if (item.RefItem != null)
{
chain.Add(item.RefItem, null);
ProcessNodes(chain, item.RefItem);
}
}
public static bool ValidateDataItems(List<DataItem> items)
{
foreach(var item in items)
if(!Check(item))
return false;
return true;
}
}
public static void Main()
{
var item1 = new DataItem() { ID = 1, Name = "First Item", RefItem = null };
var item2 = new DataItem() { ID = 1, Name = "First Item", RefItem = item1 };
var item3 = new DataItem() { ID = 1, Name = "First Item", RefItem = item2 };
item1.RefItem = item3;
Console.WriteLine(Checker.Check(item1));
item1.RefItem = null;
Console.WriteLine(Checker.Check(item1));
//Sample how to check all existing items
Console.WriteLine(Checker.ValidateDataItems(new List<DataItem>{item1, item2, item3}) ? "items is OK" : "One or more items have dependency");
}

Related

Display data of a class that is in another class datagridview c#

I have a class that contains data from another class:
class SecondClass
{
public FirstClass element { get; set; }
public string note { get; set; }
}
Then I create a list of class elements and display it in the datagridview.
firstarray.Add(new FirstClass() { id = 1, name = "name", password = "text" });
foreach (var item in firstarray)
{
if (item.id == 1)
{
secondarray.Add(new SecondClass() { element = item, note = "text" });
}
}
foreach (var item in secondarray)
{
Console.WriteLine(item.element.id);
}
dataGridView1.DataSource = secondarray;
And I get the wrong output of the items. How do I fix this?

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> {}
},
}
}
}
}
}
};
}

Hide empty columns in DataGridView

I'm working in c# with Windows form.
I've an item DataGridView named objGridView, used like this :
public partial class dlgDetailsObj : Form
{
public dlgDetailsObj(myInterface item)
{
InitializeComponent();
objGridView.DataSource = new BindingList<dlgItem>();
var t = new Task(() =>
{
List<dlgItem> listElements = new List<dlgItem>();
if (item is List<Person>)
{
List<Person> list = (List<Person>)item;
foreach (Person person in list)
{
listElements.Add(new dlgItem()
{
Name = person.Name,
Forname = person.Forname
});
}
}
else if (item is List<Compagny>)
{
List<Compagny> list = (List<Compagny>)item;
foreach (Compagny compagny in list)
{
listElements.Add(new dlgItem()
{
Compagny = compagny.Name
});
}
}
else
{
return;
}
foreach (dlgItem item in listElements)
{
objGridView.Invoke((MethodInvoker)delegate
{
int sel = objGridView.GetSelectedRowIndex();
((BindingList<dlgItem>)objGridView.DataSource).Add(item);
objGridView.SetSelectedRowIndex(sel);
});
}
});
t.Start();
}
}
internal class dlgItem
{
public string Name { get; set; }
public String Forname { get; set; }
public String Compagny { get; set; }
}
The class dlgDetailsObj is used to display a list of Persons/Companies and probably more object later.
My DataGridView has a DataSource filled of dlgItem. Actually all three fields are displayed, even if I only only one.
How can I define my code to display columns only if binded fields are not null ?
If you want to hide all empty columns you could iterate through the DataSource collection to determine whether the corresponding property has been set for any dlgItem object:
public dlgDetailsObj(myInterface item)
{
InitializeComponent();
objGridView.DataSource = new BindingList<dlgItem>();
var t = new Task(() =>
{
...
});
t.Start();
t.ContinueWith(task =>
{
bool displayNameColumn = false;
bool displayFornameColumn = false;
bool displayCompanyColumn = false;
foreach (dlgItem item in (BindingList<dlgItem>)objGridView.DataSource)
{
if (!string.IsNullOrEmpty(item.Name))
displayNameColumn = true;
if (!string.IsNullOrEmpty(item.Forname))
displayFornameColumn = true;
if (!string.IsNullOrEmpty(item.Compagny))
displayCompanyColumn = true;
}
objGridView.Columns[0].Visible = displayNameColumn;
objGridView.Columns[1].Visible = displayFornameColumn;
objGridView.Columns[2].Visible = displayCompanyColumn;
}, System.Threading.CancellationToken.None, TaskContinuationOptions.None, TaskScheduler.FromCurrentSynchronizationContext());
}

C# Reactive Extensions (rx) FirstOrDefault enumerates entire collection

It seems that the expected behavior of FirstOrDefault is to complete after finding an item that matches the predicate and the expected behavior of concat is to evaluate lazily. However, the following example enumerates the entire collection even though the predicate matches the first item.
(Thanks for the friendlier code Shlomo)
void Main()
{
var entities = Observable.Defer(() => GetObservable().Concat());
Entity result = null;
var first = entities.FirstOrDefaultAsync(i => i.RowId == 1).Subscribe(i => result = i);
result.Dump();
buildCalled.Dump();
}
// Define other methods and classes here
public IEnumerable<IObservable<Entity>> GetObservable()
{
var rows = new List<EntityTableRow>
{
new EntityTableRow { Id = 1, StringVal = "One"},
new EntityTableRow { Id = 2, StringVal = "Two"},
};
return rows.Select(i => Observable.Return(BuildEntity(i)));
}
public int buildCalled = 0;
public Entity BuildEntity(EntityTableRow entityRow)
{
buildCalled++;
return new Entity { RowId = entityRow.Id, StringVal = entityRow.StringVal };
}
public class Entity
{
public int RowId { get; set; }
public string StringVal { get; set; }
}
public class EntityTableRow
{
public int Id { get; set; }
public string StringVal { get; set; }
}
Is this the expected behavior? Is there a way to defer the enumeration of the objects (specifically the building in this case) until truly needed?
The following is Linqpad-friendly code equivalent to what you have:
void Main()
{
var entities = Observable.Defer(() => GetObservable().Concat());
Entity result = null;
var first = entities.FirstOrDefaultAsync(i => i.RowId == 1).Subscribe(i => result = i);
result.Dump();
buildCalled.Dump();
}
// Define other methods and classes here
public IEnumerable<IObservable<Entity>> GetObservable()
{
var rows = new List<EntityTableRow>
{
new EntityTableRow { Id = 1, StringVal = "One"},
new EntityTableRow { Id = 2, StringVal = "Two"},
};
return rows.Select(i => Observable.Return(BuildEntity(i)));
}
public int buildCalled = 0;
public Entity BuildEntity(EntityTableRow entityRow)
{
buildCalled++;
return new Entity { RowId = entityRow.Id, StringVal = entityRow.StringVal };
}
public class Entity
{
public int RowId { get; set; }
public string StringVal { get; set; }
}
public class EntityTableRow
{
public int Id { get; set; }
public string StringVal { get; set; }
}
If you change GetObservable to the following, you'll get the desired result:
public IObservable<IObservable<Entity>> GetObservable()
{
var rows = new List<EntityTableRow>
{
new EntityTableRow { Id = 1, StringVal = "One"},
new EntityTableRow { Id = 2, StringVal = "Two"},
};
return rows.ToObservable().Select(i => Observable.Return(BuildEntity(i)));
}
It appears the implementation of Concat<TSource>(IEnumerable<IObservable<TSource>>) is eager in evaluating the enumerable, whereas the implementation of Concat<TSource>(IObservable<IObservable<TSource>>) and ToObservable<TSource>(IEnumerable<TSource>) maintain laziness appropriately. I can't say I know why.

Set and Get a collection in C#

I have two classes: Group and Item.
public class Group
{
public string Name{ get; set; }
public List<Item> ItemList { get; set; }
}
And then Item
public class Item
{
public int ID{ get; set; }
public string Name{ get; set; }
public string Description{ get; set; }
public Group ItemGroup {get;set;}
}
Each group show have a set of items.
The following code is meant to get the list of items of a particular group, and it works when the ItemGroup in the Items class is set to type string, but not as a type Group.
public IEnumerable<Item> GetItemByGroup(string group)
{
return repository.GetAllItems().Where(
p => string.Equals(p.ItemGroup, group, StringComparison.OrdinalIgnoreCase));
}
How to change the code to get the list of items in a group by its Name property which is set in the Group class.
And how do I set a list/collection of Items in the Group class
I think this should work. Give it a hit
public IEnumerable<Item> GetItemByGroup(string group)
{
return repository.GetAllItems().Where(p =>p.ItemGroup.Name.Equals(group));
}
Update
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication2
{
class Program
{
static void Main(string[] args)
{
List<Item> list = new List<Item>();
Item i = new Item()
{
ID = 1,
Name = "Amit",
Description = "Test",
ItemGroup = new Group() { Name = "A" }
};
list.Add(i);
i = new Item()
{
ID = 2,
Name = "Amit1",
Description = "Test1",
ItemGroup = new Group() { Name = "A1" }
};
list.Add(i);
i = new Item()
{
ID = 3,
Name = "Amit11",
Description = "Test11",
ItemGroup = new Group() { Name = "A11" }
};
list.Add(i);
i = new Item()
{
ID = 4,
Name = "Amit111",
Description = "Test111",
ItemGroup = new Group() { Name = "A111" }
};
list.Add(i);
i = new Item()
{
ID = 9,
Name = "Amit4a",
Description = "Test4a",
ItemGroup = new Group() { Name = "A111" }
};
list.Add(i);
i = new Item()
{
ID = 5,
Name = "Amit5",
Description = "Test5",
ItemGroup = new Group() { Name = "A111" }
};
list.Add(i);
i = new Item()
{
ID = 6,
Name = "Amit6",
Description = "Test6",
ItemGroup = new Group() { Name = "A111" }
};
list.Add(i);
var list1 = list.Where(p => p.ItemGroup.Name.Equals("A111"));
// Console.Write(list1.Count());
foreach (var item in list1)
{
Console.WriteLine(string.Format("ID: {0} Name: {1} Description: {2} Group: {3}",item.ID,item.Name,item.Description,item.ItemGroup.Name));
}
Console.Read();
}
}
public class Group
{
public string Name { get; set; }
}
public class Item
{
public int ID { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public Group ItemGroup { get; set; }
}
}

Categories

Resources