1

我必须比较两个幻灯片类型的列表,其中包含另一个项目列表,称为图表。我必须找到幻灯片列表之间的所有差异,其中的差异可能是:

列表 A 中的幻灯片,但不在 B 中

列表 A 中的幻灯片,但不在 B 中

两个列表中的幻灯片,但它们的图表不同

我尝试使用except,但它返回具有不同图表的列表作为“相同”。示例列表 A:ABCD 列表 B:ABCD*(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;
    }
}
4

2 回答 2

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 > 0 否则 result.Count 为零。

快速修复可能是:

var result2 = s2Charts.Except(s1Charts, new PPChartComparer()).ToList();

return result.Count == 0 and result2.Count == 0;
于 2013-06-21T11:50:21.603 回答
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);
}
于 2013-06-21T11:54:30.923 回答