C# C语言中的泛型列表比较#
我有一个方法,可以使用字典查找两个int列表之间的差异。本质上,代码循环第一个列表,将每个int添加到字典中,并设置(在尚未出现的地方设置为1)/增加值。然后,它循环第二个列表设置(如果尚未出现,则为-1)/递减该值C# C语言中的泛型列表比较#,c#,linq,generics,C#,Linq,Generics,我有一个方法,可以使用字典查找两个int列表之间的差异。本质上,代码循环第一个列表,将每个int添加到字典中,并设置(在尚未出现的地方设置为1)/增加值。然后,它循环第二个列表设置(如果尚未出现,则为-1)/递减该值 一旦它循环了两个列表,您将得到一个字典,其中值=0的键表示匹配,值>=1的键表示仅在第一个列表中存在,值您可以使用泛型执行此操作: public static Dictionary<T, int> CompareLists<T>(List<T>
一旦它循环了两个列表,您将得到一个字典,其中值=0的键表示匹配,值>=1的键表示仅在第一个列表中存在,值您可以使用泛型执行此操作:
public static Dictionary<T, int> CompareLists<T>(List<T> listA, List<T> listB)
{
// 0 Match
// <= -1 listB only
// >= 1 listA only
var recTable = new Dictionary<T, int>();
foreach (T value in listA)
{
if (recTable.ContainsKey(value))
recTable[value]++;
else
recTable[value] = 1;
}
foreach (T value in listB)
{
if (recTable.ContainsKey(value))
recTable[value]--;
else
recTable[value] = -1;
}
return recTable;
}
公共静态字典比较列表(列表A、列表B)
{
//0匹配
//=仅1个listA
var recTable=新字典();
foreach(列表A中的T值)
{
if(recTable.ContainsKey(值))
可纠正[值]+;
其他的
recTable[值]=1;
}
foreach(列表B中的T值)
{
if(recTable.ContainsKey(值))
可纠正的[值]——;
其他的
recTable[值]=-1;
}
返回可纠正;
}
要回答您的第二个问题,以下是如何使其更通用:
public static Dictionary<T, int> CompareLists<T>(IEnumerable<T> listA,
IEnumerable<T> listB, IEqualityComparer<T> comp)
{
var recTable = new Dictionary<T, int>(comp);
foreach (var value in listA)
{
if (recTable.ContainsKey(value))
recTable[value]++;
else
recTable[value] = 1;
}
foreach (var value in listB)
{
if (recTable.ContainsKey(value))
recTable[value]--;
else
recTable[value] = -1;
}
return recTable;
}
下面是一个实现IEqualityComparer的示例。这将所有奇数整数视为相等,所有偶数整数视为相等:
public class MyEq : IEqualityComparer<int>
{
public bool Equals(int x, int y)
{
return (x % 2) == (y % 2);
}
public int GetHashCode(int obj)
{
return (obj % 2).GetHashCode();
}
}
公共类MyEq:IEqualityComparer
{
公共布尔等于(整数x,整数y)
{
返回(x%2)=(y%2);
}
公共int GetHashCode(int obj)
{
返回(对象%2)。GetHashCode();
}
}
FullOuterJoin,如下所示:
公共静态字典比较列表(列表A、列表B)
{
返回listA.FullOuterJoin(listB,
a=>a,//从列表a比较什么
b=>b,//从列表b比较什么
(a、b、键)=>
new{key=key,value=0},//如果在两者中都找到,则返回什么
new{key=key,value=-1},//如果只在
new{key=key,value=1})//如果仅在B中找到,则返回什么
.ToDictionary(a=>a.key,a=>a.value);//仅因为您需要字典
}
这是我的两分钱:
public static Dictionary<T, int> CompareLists<T>(List<T> left, List<T> right, IEqualityComparer<T> comparer)
{
Dictionary<T, int> result = left.ToDictionary(l => l, l => right.Any(r => comparer.Equals(l, r)) ? 0 : -1);
foreach (T r in right.Where(t => result.Keys.All(k => !comparer.Equals(k, t))))
result[r] = 1;
return result;
}
公共静态字典比较器列表(左列表、右列表、IEqualityComparer比较器)
{
字典结果=left.ToDictionary(l=>l,l=>right.Any(r=>comparer.Equals(l,r))?0:-1);
foreach(右侧的tr.Where(T=>result.Keys.All(k=>!comparer.Equals(k,T)))
结果[r]=1;
返回结果;
}
该方法使用任何类型的T
的List
s和该类型的T
的IEqualityComparer
。然后,它首先生成包含在“left”列表中的那些元素的字典,从而检查它们是否也在“right”列表中,并相应地设置值
第二步添加仅包含在“right”列表中的元素,其值为1
这是否是一个合理的实现取决于您试图用它实现什么。我认为它很短,但仍然可读,依赖于LINQ方法的正确实现。尽管可能有更快的可能性,但如果这是针对真正大的列表或经常调用的方法,则可以考虑。首先,这是一个合理的实现吗?
可能更适合CodeReview站点,因为它是工作代码我想要一个可以处理任何对象的东西,调用方可以在其中定义比较逻辑
您签出了吗?(编辑:或实际上?)看看这里,如果您有相同的值在listA
中出现两次,在listB
中出现一次,那么它将无法正常工作,结果将是肯定的,在您的注释中显示“仅listA”。您刚刚重新创建了完整的外部联接。什么是合理的实现?如果你解释了你的功能背后的目的,人们可以提出一种更好的方法来实现它。多亏了这一点,它非常适合我想做的事情。我很难看出这比user2023861发布的解决方案更简洁/更好?很高兴接受再教育,只是看不到吗?好吧,这种方法适用于所有类型的集合、列表,它是通用的,因为它允许您确定要比较什么和保留什么。当然,在您的情况下,您只需要返回0、-1或1,但是如果您想要整个记录呢?或者你想比较一个对象列表的属性(或者多个属性)?这也是一个定义良好的已知方法(尽管实现相当新),已经存在了30年:使用FullOuterJoin,列表类型不必是相同的类型。它们也可以是完整的对象,您不必编写自定义的IEqualityComparer,只需列出要比较的对象的属性即可。它非常适合其他LINQ方法,并且可以很容易地转换为SQL(完全外部连接)。您还可以返回部分对象,或合并每个对象的一部分。它是尽可能通用的,每个人都应该从名称中了解完整外部联接的作用。感谢提供更多详细信息。与完全外部连接的概念相比,我所面临的更多的是新的实现。它的好处现在更有意义了。当然,这不适用于您增加的在一个或两个列表中多次出现同一个键的要求。
public class MyEq : IEqualityComparer<int>
{
public bool Equals(int x, int y)
{
return (x % 2) == (y % 2);
}
public int GetHashCode(int obj)
{
return (obj % 2).GetHashCode();
}
}
public static Dictionary<int, int> CompareLists(List<int> listA, List<int> listB)
{
return listA.FullOuterJoin(listB,
a=>a, // What to compare from ListA
b=>b, // What to compare from ListB
(a,b,key)=>
new {key=key,value=0}, // What to return if found in both
new {key=key,value=-1},// What to return if found only in A
new {key=key,value=1}) // What to return if found only in B
.ToDictionary(a=>a.key,a=>a.value); // Only because you want a dictionary
}
public static Dictionary<T, int> CompareLists<T>(List<T> left, List<T> right, IEqualityComparer<T> comparer)
{
Dictionary<T, int> result = left.ToDictionary(l => l, l => right.Any(r => comparer.Equals(l, r)) ? 0 : -1);
foreach (T r in right.Where(t => result.Keys.All(k => !comparer.Equals(k, t))))
result[r] = 1;
return result;
}