我必须比较两个类型为Slide的列表,其中包含另一个项目列表,称为图表。 我必须找到幻灯片列表之间的所有差异,其中差异可能是:
列表A中的幻灯片,但不是B
列表A中的幻灯片,但不是B
两张列表中的幻灯片,但它们的图表不同
我尝试使用except,但它返回列表与不同的图表“相同”。 例 清单A:A B C D. 清单B:A B C D *(d包含不同的图表) 应该返回D *,但这不起作用。
我对为什么会发生这种情况感到有点困惑 - 比较对我来说还不错。
我的代码:
class PPDetectDifferences
{
private PPPresentation laterVersion;
private string Path { get; set; }
private PPPresentation OriginalPresentation { get; set; }
private PPPresentation GetLaterPresentation()
{
var ppDal = new PPDAL(Path);
Task<PPPresentation> task = Task.Run(() => ppDal.GetPresentation());
var presentation = task.Result;
return presentation;
}
public PPDetectDifferences(string path, PPPresentation ppPresentation)
{
if (path != null)
{
this.Path = path;
}
else
{
throw new ArgumentNullException("path");
}
if (ppPresentation != null)
{
this.OriginalPresentation = ppPresentation;
}
else
{
throw new ArgumentNullException("ppPresentation");
}
}
public bool IsDifferent()
{
//// getting the new List of Slides
laterVersion = GetLaterPresentation();
//// Compare the newer version with the older version
var result = laterVersion.Slides.Except(OriginalPresentation.Slides, new PPSlideComparer()).ToList();
//// If there are no differences, result.count should be 0, otherwise some other value.
return result.Count != 0;
}
}
/// <summary>
/// Compares two Slides with each other
/// </summary>
public class PPSlideComparer : IEqualityComparer<PPSlide>
{
public int GetHashCode(PPSlide slide)
{
if (slide == null)
{
return 0;
}
//// ID is an INT, which is unique to this Slide
return slide.ID.GetHashCode();
}
public bool Equals(PPSlide s1, PPSlide s2)
{
var s1Charts = (from x in s1.Charts select x).ToList();
var s2Charts = (from x in s2.Charts select x).ToList();
var result = s1Charts.Except(s2Charts, new PPChartComparer()).ToList();
return result.Count == 0;
}
}
/// <summary>
/// Compares two Charts with each other
/// </summary>
public class PPChartComparer : IEqualityComparer<PPChart>
{
public int GetHashCode(PPChart chart)
{
//// UID is an INT, which is unique to this chart
return chart == null ? 0 : chart.UID.GetHashCode();
}
public bool Equals(PPChart c1, PPChart c2)
{
var rvalue = c1.UID == c2.UID;
if (c1.ChartType != c2.ChartType)
{
rvalue = false;
}
return rvalue;
}
}
答案 0 :(得分:2)
你的比较似乎是错误的。如果您使用except
来比较列表,则必须以两种方式执行此操作。
来自MSDN:
“此方法首先返回那些未出现在第二个元素中的元素。它也不会返回第二个中没有出现的元素。”
在你的情况下:
public bool Equals(PPSlide s1, PPSlide s2)
{
var s1Charts = (from x in s1.Charts select x).ToList();
var s2Charts = (from x in s2.Charts select x).ToList();
var result = s1Charts.Except(s2Charts, new PPChartComparer()).ToList();
return result.Count == 0;
}
如果s1Charts
的元素多于s2Charts
,则result.Count&gt;否则为result.Count为零。
快速修复可能是:
var result2 = s2Charts.Except(s1Charts, new PPChartComparer()).ToList();
return result.Count == 0 and result2.Count == 0;
答案 1 :(得分:1)
要使用except比较两个序列,您需要检查两个方向。例如:
List<T> a, b;
IEqualityComparer<T> cmp = ...
var areEqual = !a.Except(b, cmp).Concat(b.Except(c, cmp)).Any();
此问题在您的代码中出现两次:首先是在比较2个幻灯片列表时,再次是在比较2个图表列表时。
使用Except()
进行集合比较时需要注意的另一件事是它充当集合操作。因此,{ A, A, A }.Except({ A })
将返回空。
因此,我建议更像以下内容:
public static bool CollectionEquals<T>(this ICollection<T> @this, ICollection<T> that, IEqualityComparer<T> cmp = null)
{
// to be equal, the 2 collections must not be null unless they're both null or have the same count
if (ReferenceEquals(@this, that)) { return true; }
if (@this == null || that == null) { return false; }
if (@this.Count != that.Count) { return false; }
// use the default comparer if one wasn't passed in
var comparer = cmp ?? EqualityComparer<T>.Default;
// to handle duplicates, we convert @this into a "bag" (a mapping
// from value -> # occurrences of that value in the collection
var thisDict = @this.GroupBy(t => t, comparer)
.ToDictionary(g => g.Key, g => g.Count(), comparer);
// do the same for that
var thatDict = @this.GroupBy(t => t, comparer)
.ToDictionary(g => g.Key, g => g.Count(), comparer);
// the two collections are equal if they have the same number of distinct values
return thisDict.Count == thatDict.Count
// and if, for each distinct value in @this, that value is also in that
// and has the same number of occurrences in @this and that
&& thisDict.All(kvp => thatDict.ContainsKey(kvp.Key)
&& thatDict[kvp.Key] == kvp.Value);
}