How to generate a table/matrix with dynamic nested class - c#

How to generate a table (matrix or another type of list/class) for each option with a dynamic list of tags.
There can be a (x) amount of Options and each option can have (y) amount of tags.
Option Class
public class Option
{
public Option()
{
Tags = new HashSet<Tag>();
}
public string Name { get; set; }
public ICollection<Tag> Tags { get; set; }
}
Tag Class
public class Tag
{
public string Value { get; set; }
}
Main Code
var option1 = new Option() { Name = "Option1" };
var option2 = new Option() { Name = "Option2" };
option1.Tags = new List<Tag>();
option2.Tags = new List<Tag>();
var tag1 = new Tag() { Value = "tag1" };
var tag2 = new Tag() { Value = "tag2" };
var tag3 = new Tag() { Value = "tag3" };
var tag4 = new Tag() { Value = "tag4" };
var tag5 = new Tag() { Value = "tag5" };
option1.Tags.Add(tag1);
option1.Tags.Add(tag2);
option2.Tags.Add(tag3);
option2.Tags.Add(tag4);
option2.Tags.Add(tag5);
Expected outcome:
//Console Output
tag1 tag3
tag1 tag4
tag1 tag5
tag2 tag3
tag2 tag4
tag2 tag5
Code I have so far but not quite working.( Using GenFu to generate data)
private static void Main(string[] args)
{
List<List<Tag>> TagList = new List<List<Tag>>();
List<int> TagOrder = new List<int>();
List<Option> Options = A.ListOf<Option>(2);
foreach (Option option in Options)
{
option.Tags = A.ListOf<Tag>(2);
}
foreach (Option option in Options)
{
TagList.Add(option.Tags.ToList());
}
foreach (var item in TagList)
{
TagOrder.Add(item.Count);
}
int run = 0;
int optionrun = 0;
var runCount = TagOrder.Aggregate((x, y) => x * y);
for (int h = 0; h < runCount + 1; h++)
{
try
{
var word = Options[optionrun].Tags.ToList()[run].Value;
Console.WriteLine(word);
optionrun++;
}
catch (Exception)
{
optionrun = 0;
run++;
Console.WriteLine("");
}
}
Console.ReadLine();
static int RandomNumber(int min, int max)
{
Random random = new Random(); return random.Next(min, max);
}
}

Related

Lambda expression for filtering 5 nested classes

I have a nested object and I must filter it based on the deeper level.
These are my classes:
class Library {
public string Name { get; set; }
public IList<Section> Sections { get; set; }
public Library (string name, IList<Section> sections = null) {
Name = name;
Sections = sections ?? new List<Section>();
}
}
class Section {
public string Name { get; set; }
public IList<Book> Books { get; set; }
public Section(string name, IList<Book> books = null) {
Name = name;
Books = books ?? new List<Book>();
}
}
class Book {
public string Name { get; set; }
public IList<Word> Words { get; set; }
public Book(string name, IList<Word> words = null) {
Name = name;
Words = words ?? new List<Word>();
}
}
class Word {
public string Name { get; set; }
public IList<Character> Characters { get; set; }
public Word(string name, IList<Character> characters = null) {
Name = name;
Characters = characters ?? new List<Character>();
}
}
class Character {
public char chrctr { get; set; }
public Character(char character){
chrctr = character;
}
}
this is my object:
var char1 = new Character('a');
var char2 = new Character('b');
var char3 = new Character('c');
var char4 = new Character('d');
var char5 = new Character('e');
var word1 = new Word("word1", new Character[] { char1 });
var word2 = new Word("word2", new Character[] { char1, char2 });
var word3 = new Word("word3", new Character[] { char1, char2, char3 });
var word4 = new Word("word4", new Character[] { char1, char2, char3, char4 });
var word5 = new Word("word5", new Character[] { char1, char2, char3, char4, char5 });
var book1 = new Book("book1", new Word[] { word1 });
var book2 = new Book("book2", new Word[] { word1, word2 });
var book3 = new Book("book3", new Word[] { word1, word2, word3 });
var section1 = new Section("section1", new Book[] { book1, book2 });
var section2 = new Section("section2", new Book[] { book1, book2, book3 });
var library = new Library("library1", new Section[] { section1, section2 });
I want to replace my nested foreach with lambda expression for getting the filtered object, without using "add" and "get" functions for creating a new object:
var filteredLibrary = new Library("filteredLibrary");
foreach (var section in library.Sections)
{
foreach (var book in section.Books)
{
foreach (var word in book.Words)
{
var chars = word.Characters.Where(c => c.chrctr == 'd').ToList();
if (chars.Count > 0)
{
filteredLibrary.Sections.Add(section); //if it doesn't exist
filteredLibrary.GetSection(section.Name).Books.Add(book); //if it doesn't exist
filteredLibrary.GetSection(section.Name).GetBook(book.Name).Words.Add(chars); //if it doesn't exist
}
}
}
}
How can I do this?
I am not sure you should go this route as the whole thing, generally, looks a bit too complex. I'd try to simplify logic first.
Otherwise, here is what ReSharper suggests (using query syntax)
var filteredLibrary = new Library("filteredLibrary");
foreach (var section in
from section in library.Sections
from book in section.Books
from word in book.Words
let chars = word.Characters
.Where(c => c.chrctr == 'd')
.ToList()
where chars.Count > 0
select section)
{
//if it doesn't exist
filteredLibrary.Sections.Add(section);
filteredLibrary.GetSection(section.Name).Books.Add(book);
filteredLibrary.GetSection(section.Name).GetBook(book.Name).Words.Add(chars);
}

How to create a multi-line string in a tree structure using a recursive method?

I have this model:
public class TreeModel
{
public int Id { get; set; }
public int? ParentId { get; set; }
public string Name { get; set; }
public static List<TreeModel> GetData()
{
var list = new List<TreeModel>()
{
new TreeModel() {Id = 1,ParentId = null,Name = "Name1"},
new TreeModel() {Id = 2,ParentId = null,Name = "Name2"},
new TreeModel() {Id = 3,ParentId = null,Name = "Name3"},
new TreeModel() {Id = 4,ParentId = 1,Name = "Name4"},
new TreeModel() {Id = 5,ParentId = 1,Name = "Name5"},
new TreeModel() {Id = 6,ParentId = 4,Name = "Name6"},
new TreeModel() {Id = 7,ParentId = 6,Name = "Name7"},
};
return list;
}
public static string ShowTree(List<TreeModel> source)
{
var text = "";
foreach (var item in source)
{
if (item.ParentId != null) continue;
text += item.Name + "\n";
var childs = source.Where(x => x.ParentId == item.Id).ToList();
if (!childs.Any()) continue;
{
foreach (var child in childs)
{
text += " " + child.Name + "\n"; //2 spaces
var childs2 = source.Where(x => x.ParentId == child.Id).ToList();
if (!childs2.Any()) continue;
{
foreach (var child2 in childs2)
{
text += " " + child2.Name + "\n"; //4 spaces
var childs3 = source.Where(x => x.ParentId == child2.Id).ToList();
if (!childs3.Any()) continue;
foreach (var child3 in childs3)
{
text += " " + child3.Name + "\n"; //6 spaces
}
}
}
}
}
}
return text;
}
}
with my method ShowTree, I am able to get this:
Name1
Name4
Name6
Name7
Name5
Name2
Name3
Can someone help me transform this method in recursive one, in order to use it with a larger data-set.
Just call the ShowTree method and you will get your formatted data.
Edit: Using StringBuilder because of better performance:
public static string ShowTree(List<TreeModel> source) {
var empty = new StringBuilder();
source.Where(s => s.ParentId == null).ToList().ForEach(s => ShowNode(source, s, empty));
return empty.ToString();
}
private static void ShowNode(List<TreeModel> source, TreeModel model, StringBuilder text, int depth = 0) {
text.Append(Enumerable.Repeat(" ", depth++).Aggregate("", (s, s1) => s + s1) + model.Name + "\n");
source.ForEach(m => {
if (model.Id == m.ParentId) ShowNode(source, m, text, depth);
});
}
You need to use a recursive function :
public static string ShowTree(List<TreeModel> source)
{
var buffer = new StringBuilder();
foreach (var item in source.Where(x => !x.ParentId.HasValue))
{
WriteTree(buffer, source, item);
}
return buffer.ToString();
}
private static void WriteTree(StringBuilder buffer, List<TreeModel> source, TreeModel item, int level = 0)
{
buffer.AppendLine(new string('\t', level) + item.Name);
foreach (var child in source.Where(x => x.ParentId == item.Id))
{
WriteTree(buffer, source, child, level + 1);
}
}
Try following code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ProgrammingBasics
{
class Program
{
static void Main(string[] args)
{
TreeModel model = new TreeModel();
string text = model.ShowTree();
Console.WriteLine(text);
Console.ReadLine();
}
}
public class TreeModel
{
public int Id { get; set; }
public int? ParentId { get; set; }
public string Name { get; set; }
public static List<TreeModel> GetData()
{
var list = new List<TreeModel>()
{
new TreeModel() {Id = 1,ParentId = null,Name = "Name1"},
new TreeModel() {Id = 2,ParentId = null,Name = "Name2"},
new TreeModel() {Id = 3,ParentId = null,Name = "Name3"},
new TreeModel() {Id = 4,ParentId = 1,Name = "Name4"},
new TreeModel() {Id = 5,ParentId = 1,Name = "Name5"},
new TreeModel() {Id = 6,ParentId = 4,Name = "Name6"},
new TreeModel() {Id = 7,ParentId = 6,Name = "Name7"},
};
return list;
}
public string ShowTree()
{
int level = 0;
return ShowTreeRecursive(GetData(), level, null);
}
public static string ShowTreeRecursive(List<TreeModel> source, int level, int? ParentId)
{
string text = "";
foreach(var node in source.Where(x => x.ParentId == ParentId))
{
text += string.Format("{0} {1}\n", new string(' ', 3 * level), node.Name);
text += ShowTreeRecursive(source, level + 1, node.Id);
}
return text;
}
}
}

how to add list of class inside of class (preferably with reflection if possible)

I have a list of type class, and I want to add up the members inside, how do I go about to achieve this?
void Main()
{
var a1 = new A(){id =2};
var a2 = new A(){id =3, xx=1};
var a3 = new A(){id =2, yy=2};
var a4 = new A(){id =2, xx=4, yy=6};
var a5 = new A(){cc = new C(){id =2, xx=1}};
var a6 = new A(){cc = new C(){id =2}};
var a7 = new A(){cc = new C(){id =2}};
var b = new B();
b.SomeMethod(new List<A>{a1, a2, a3, a4, a5, a6, a7});
}
Class C is used inside class A. Both classes are 3pty API, so I cant modify it.
public class A
{
public int id {get;set;}
public int xx {get;set;}
public int yy {get;set;}
public C cc {get; set;}
}
public class C
{
public int id {get;set;}
public int xx {get;set;}
public int yy {get;set;}
}
Now instead of adding up single member of the class in the list of class, I need the a return of class where all the member inside of the class are added up.
public class B
{
public void SomeMethod(IList<A> listOfA)
{
int result1 = listOfA.Sum(A => A.id);//return 9
int result2 = listOfA.Sum(A => A.xx);//return 5
int result3 = listOfA.Sum(A => A.yy);//return 8
int result4 = listOfA.Where(A=>A.cc != null).Sum(A => A.cc.id);
//return 6
//var resultAll = ???;//return new A(){id = 9, xx = 5, yy = 8, cc = new C(){id =6, xx = 1}}
}
}
Basically I need help on how to achieve result as below from above
//var resultAll = ???;//return new A(){id = 9, xx = 5, yy = 8, cc = new C(){id =6, xx = 1}}
You need to ensure that you are checking for null values before computing the sum. Following code should work
int result4 = listOfA.Where(A=>A.cc != null).Sum(A => A.cc.id);
int result5 = listOfA.Where(A=>A.cc != null).Sum(A => A.cc.xx);
var resultAll = new A() {
id = result1,
xx = result2,
yy = result3,
cc = new C()
{
id = result4,
xx = result5
}
};
If I understood correctly, check this code, might help:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CSharpConsoleApplication.Tests
{
class OperatorsOverloadingTest
{
public static void Run()
{
var list = new List<ParentObject>() {
new ParentObject() { IntegerValue = 1 },
new ParentObject() { IntegerValue = 2 },
new ParentObject() { Child = new ChildObject() { DoubleValue = 10D } },
new ParentObject() { Child = new ChildObject() { DoubleValue = 20D } }
};
ParentObject pTotal = new ParentObject();
foreach (var p in list)
pTotal += p;
Console.WriteLine(pTotal);
}
}
public class ParentObject
{
public int IntegerValue { get; set; }
public ChildObject Child { get; set; }
public ParentObject()
{
Child = new ChildObject();
}
public static ParentObject operator +(ParentObject item1, ParentObject item2)
{
var parent = new ParentObject() { IntegerValue = item1.IntegerValue + item2.IntegerValue };
parent.Child = item1.Child + item2.Child;
return parent;
}
public override string ToString()
{
return string.Format("IntegerValue={0}, Child={1}", IntegerValue, Child);
}
}
public class ChildObject
{
public double DoubleValue { get; set; }
public static ChildObject operator +(ChildObject item1, ChildObject item2)
{
return new ChildObject() { DoubleValue = item1.DoubleValue + item2.DoubleValue };
}
public override string ToString()
{
return string.Format("DoubleValue={0}", DoubleValue);
}
}
}

Creating a hierarchical structure from a list of sequence strings

Given a list of sequence strings, what's the best way to create a hierarchical structure from it?
A sample of the type of list of sequence strings is below:
List<string> sequenceList = new List<string>() { "1", "1.1", "1.2", "2", "2.1", "2.1.1", "2.1.2" };
I've included an initial pass of the code below too:
public class Hierarchy
{
public int ID { get; set; }
public int ParentID { get; set; }
}
public IList<Hierarchy> GetHierarchy(IList<string> sequenceList)
{
int iD = 0;
List<Hierarchy> hierarchy = new List<Hierarchy>();
foreach (string sequence in sequenceList)
{
iD++;
List<string> childSequence = new List<string>();
string[] sequenceParts = sequence.Split(new char[] { '.' }, StringSplitOptions.RemoveEmptyEntries);
// If the sequence contains sub-sequence, i.e. "2.1" is a sub-sequence of "2".
if (sequenceParts.Count() > 1)
{
// Struggling with this part, how to obtain the child sequence...
childSequence = sequenceList.Where(s => s.Substring(0, (s.Length - 2)) == sequence.Substring(0, (s.Length - 2))).ToList();
if (childSequence.Count() > 0)
{
int parentID = iD;
foreach (string subSequence in childSequence)
hierarchy.Add(new Hierarchy() { ID = iD, ParentID = parentID });
}
}
else
// Add top level.
hierarchy.Add(new Hierarchy() { ID = iD, ParentID = 0 });
}
return (IList<Hierarchy>)hierarchy;
}
I suspect I'm missing a trick with recursion on this so any help would be greatly appreciated.
It would help a bit to add Sequence property to the class and use it to find the parent:
public class Hierarchy
{
public int ID { get; set; }
public int ParentID { get; set; }
public string Sequence { get; set; }
}
public static IList<Hierarchy> GetHierarchy(IList<string> sequenceList)
{
int iD = 0;
List<Hierarchy> hierarchy = new List<Hierarchy>();
foreach (string sequence in sequenceList)
{
iD++;
List<string> childSequence = new List<string>();
string[] sequenceParts = sequence.Split(new char[] { '.' }, StringSplitOptions.RemoveEmptyEntries);
// If the sequence contains sub-sequence, i.e. "2.1" is a sub-sequence of "2".
if (sequenceParts.Count() > 1)
{
var parentSequence = sequence.Substring(0, sequence.LastIndexOf("."));
var parent = hierarchy.Single(x => x.Sequence == parentSequence);
hierarchy.Add(new Hierarchy() { ID = iD, ParentID = parent.ID, Sequence = sequence });
}
else
// Add top level.
hierarchy.Add(new Hierarchy() { ID = iD, ParentID = 0, Sequence = sequence });
}
return (IList<Hierarchy>)hierarchy;
}
EDITED: this version uses recursion
public class Hierarchy
{
public int ID { get; set; }
public int ParentID { get; set; }
}
public static IList<Hierarchy> GetHierarchy(IList<string> sequenceList)
{
int iD = 0;
List<Hierarchy> hierarchy = new List<Hierarchy>();
foreach (string sequence in sequenceList.Where(x => x.Count(f => f == '.') == 0)) // get the root nodes
{
iD++;
var item = new Hierarchy() { ID = iD, ParentID = 0 };
hierarchy.Add(item);
hierarchy.AddRange(GetChildsRecursive(sequence, item.ID, sequenceList, () => ++iD));
}
return (IList<Hierarchy>)hierarchy;
}
private static IList<Hierarchy> GetChildsRecursive(string parentSequence, int parentId, IList<string> sequences, Func<int> idGenerator)
{
var parentDots = parentSequence.Count(f => f == '.');
var childSequences = sequences.Where(x => x.StartsWith(parentSequence) && x.Count(f => f == '.') == parentDots + 1);
var list = new List<Hierarchy>();
foreach (var childSequence in childSequences)
{
var item = new Hierarchy() { ID = idGenerator(), ParentID = parentId };
list.Add(item);
list.AddRange(GetChildsRecursive(childSequence, item.ID, sequences, idGenerator));
}
return list;
}

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

Resources