c# - Improving Generic List Comparator -
i need generic class compare 2 list instances. have code below, quite messy , inefficient. how can make better , faster?
callbyname extension uses reflection property.
public class listobjectcomparator { #region proprietes public list<object> newlist {get; private set;} public list<object> removedlist { get; private set; } public list<object> communlist { get; private set; } #endregion #region methodes publics public bool run<t>(string icommuntextpropertyname, list<t> ioriginallist, list<t> inewlist) { return run(icommuntextpropertyname, ioriginallist, icommuntextpropertyname, inewlist); } public bool run<t>(string ioriginalpropertyname, list<t> ioriginallist,string inewpropertyname, list<t> inewlist) { if (ioriginalpropertyname.isnotnull() && inewpropertyname.isnotnull() && ioriginallist != null && inewlist != null) { newlist = new list<object>(); removedlist = new list<object>(); communlist = new list<object>(); foreach (object originalitem in ioriginallist) { object research = inewlist.where(a => a.callbyname(inewpropertyname).tostring() == originalitem.callbyname(ioriginalpropertyname).tostring()).firstordefault(); if (research == null) { removedlist.add(originalitem); } else { communlist.add(research); } } foreach (object newitem in inewlist) { object research = ioriginallist.where(a => a.callbyname(ioriginalpropertyname).tostring() == newitem.callbyname(inewpropertyname).tostring()).firstordefault(); if (research == null) { newlist.add(newitem); }; } return true; } return false; } }
answer:
public class listcomparator<toriginal,tnew> { public listcomparator(ienumerable<toriginal> ioriginallist, func<toriginal, icomparable> ioriginalproperty, ienumerable<tnew> inewlist, func<tnew, icomparable> inewproperty) { if (ioriginalproperty == null || inewproperty == null) { throw new argumentnullexception(); }; if (ioriginallist.isnullorempty() ) { newlist = (inewlist != null) ? inewlist.tolist() : null; return; } if (inewlist.isnullorempty()) { removedlist = (ioriginallist != null) ? ioriginallist.tolist() : null; return; } newlist = (from tnew in inewlist.tolist() join toriginal in ioriginallist.tolist() on inewproperty(tnew) equals ioriginalproperty(toriginal) gj item in gj.defaultifempty() item == null select tnew).tolist(); communlist = (from tnew in inewlist.tolist() join toriginal in ioriginallist.tolist() on inewproperty(tnew) equals ioriginalproperty(toriginal) gj item in gj.defaultifempty() item != null select tnew).tolist(); communpairlist = (from tnew in inewlist.tolist() join toriginal in ioriginallist.tolist() on inewproperty(tnew) equals ioriginalproperty(toriginal) gj item in gj.defaultifempty() item != null select new keyvaluepair<toriginal, tnew>(item, tnew)).tolist(); removedlist = (from toriginal in ioriginallist.tolist() join tnew in inewlist.tolist() on ioriginalproperty(toriginal) equals inewproperty(tnew) gj item in gj.defaultifempty() item == null select toriginal).tolist(); return; } #region proprietes public list<tnew> newlist { get; private set; } public list<toriginal> removedlist { get; private set; } public list<tnew> communlist { get; private set; } /// <summary> /// obtient la liste de pair avec l'original en key et le nouveau en value /// </summary> public list<keyvaluepair<toriginal,tnew>> communpairlist { get; private set; } #endregion }
use:
list<tuple<string, string>> list1 = new list<tuple<string, string>>(); list<tuple<string, string>> list2 = new list<tuple<string, string>>(); list1.add(new tuple<string, string>("aa", "zefzef")); list1.add(new tuple<string, string>("a1", "iulyu")); list2.add(new tuple<string, string>("abb", "szefez")); list2.add(new tuple<string, string>("a1", "zevzez")); listcomparator<tuple<string, string>, tuple<string, string>> comp = new listcomparator<tuple<string, string>, tuple<string, string>>(list1, x => x.item1, list2, => a.item1);
output :
1 commun, 1 removed, 1 new
thanks
to list of items 2 lists share in common, @ enumerable.intersect. is:
var same = originallist.intersect(newlist, comparer);
if want know items in newlist
aren't in originallist
(i.e. list of added items), you'd use enumerable.except:
var added = newlist.except(originallist, comparer);
if want know items deleted, use except
again, switch order:
var deleted = originallist.except(newlist, comparer);
if you're comparing different properties, best bet create intermediate lists contain properties , references objects. example: (there might typos in code, shows general idea.)
class tempobj: iequatable<tempobj> { public string key { get; set; } public object item { get; set; } public bool equals(tempobj other) { return key.equals(other.key); } public override int gethashcode() { return key.gethashcode(); } } var listorig = originallist.select(x => new tempobj( x..callbyname(ioriginalpropertyname).tostring()); var listnew = newlist.select(x => new tempobj( x.callbyname(inewpropertyname).tostring());
now can intersect
or except
on listnew
, listorig
, compare property names. can pull item
values resulting list.
Comments
Post a Comment