我需要一个泛型类来比较两个列表实例。我有下面的代码,但它非常混乱和低效。我怎样才能让它更好,更快?
CallByName是一个使用反射获取属性的扩展。
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;
}
}
答案:
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) into gj
from item in gj.DefaultIfEmpty()
where item == null
select tnew).ToList();
CommunList = (from tnew in iNewList.ToList()
join toriginal in iOriginalList.ToList()
on iNewProperty(tnew)
equals iOriginalProperty(toriginal) into gj
from item in gj.DefaultIfEmpty()
where item != null
select tnew).ToList();
CommunPairList = (from tnew in iNewList.ToList()
join toriginal in iOriginalList.ToList()
on iNewProperty(tnew)
equals iOriginalProperty(toriginal) into gj
from item in gj.DefaultIfEmpty()
where 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) into gj
from item in gj.DefaultIfEmpty()
where 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
}
使用:
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 => a.Item1);
输出:
1个通讯,1个删除,1个新
感谢
答案 0 :(得分:2)
要获取两个列表共有的项目列表,请查看Enumerable.Intersect。那就是:
var same = OriginalList.Intersect(NewList, comparer);
如果您想了解NewList
中OriginalList
中的哪些项目(即添加的项目列表),您可以使用Enumerable.Except:
var added = NewList.Except(OriginalList, comparer);
如果您想知道哪些项目已被删除,请再次使用Except
,但切换顺序:
var deleted = OriginalList.Except(NewList, comparer);
如果您要比较不同的属性,那么最好的办法是创建包含属性和对象引用的中间列表。例如:(代码中可能存在拼写错误,但这显示了一般的想法。)
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());
现在,您可以在Intersect
和Except
上执行listNew
或listOrig
,这将比较属性名称。然后,您可以从结果列表中提取Item
值。
答案 1 :(得分:1)
你的班级实际上并不是通用的(尽管它应该是),只有你的方法是。
试试这个:
public class ListObjectComparator<T>
{
#region Public Methods
public static IEnumerable<T> Run(IEnumerable<T> originalItems, IEnumerable<T> newItems, Func<T,T,bool> comparer)
{
foreach(var originalItem in originalItems)
{
bool found = false;
foreach (var newItem in newItems)
{
if (comparer(originalItem,newItem))
{
found = true;
itemToRemove = newItem;
break;
}
}
if (found)
{
newItems.Remove(itemToRemove);
yield return originalItem;
}
}
}
#endregion
}
运行将originalItems与newItems进行比较,并使用您提供的ComparePredicate返回相同的项目列表。
使用的一个例子是:
List<int> firstList;
List<int> secondList;
List<int> common = ListObjectComparator<int>.Run(firstList,secondList, ((f,s) => return f< s));
此处的比较谓词将返回list1中的所有整数,其中列表1小于列表2中的等效int。
编辑:我应该补充一点,你不应该重新发明轮子,你总是可以使用你自己的IEqualityComparer类。