繁体   English   中英

从配对列表中删除“重复项”

[英]Remove 'duplicates' from a list of pairings

标题可能会引起误解,因此请举一个例子:

我有一堂课:

class Pair
{
   Book Book1;
   Book Book2;
}

我有这些清单:

var list = new List<Pair>();

list.Add(new Pair() {
    Book1 = new Book() { Id = 123 },
    Book2 = new Book() { Id = 456 }
 });

list.Add(new Pair() {
    Book1 = new Book() { Id = 456 },
    Book2 = new Book() { Id = 123 }
 });

现在,尽管事实是“书本被“翻转”了,但我的系统仍应将它们视为副本。

我需要一种从列表中删除这些“重复项” 之一的方法(任何一个-因此,让我们先简化一下)。

我尝试过的

        var tempList = new List<Pair>();
        tempList.AddRange(pairs);

        foreach (var dup in pairs)
        {
            var toRemove = pairs.FirstOrDefault(o => o.Book1.Id == dup.Book2.Id
                                                       && o.Book2.Id == dup.Book1.Id);

            if (toRemove != null)
                tempList.Remove(toRemove);
        }

        return tempList;

这将不返回任何项目(鉴于上述示例),因为两个Pair对象都将满足lambda中的条件,不过我只删除了一个。

注意:如果我只是立即从集合中删除了元素(而不是从临时列表中删除),则不会发生这种情况-但那样的话,我将无法无例外地对其进行迭代。

您可以设置IEqualityComparer<Pair>具体类,并将其传递给.Distinct()方法:

class PairComparer : IEqualityComparer<Pair>
{
    public bool Equals(Pair x, Pair y)
    {
        return (x.Book1.Id == y.Book1.Id && x.Book2.Id == y.Book2.Id)
            || (x.Book1.Id == y.Book2.Id && x.Book2.Id == y.Book1.Id);
    }

    public int GetHashCode(Pair obj)
    {
        return obj.Book1.Id.GetHashCode() ^ obj.Book2.Id.GetHashCode();
    }
}

然后像这样使用它:

var distinctPairs = list.Distinct(new PairComparer());

问题是您要删除两个重复项。

尝试这个:

var uniquePairs = list.ToLookup( p => Tuple.Create(Math.Min(p.Book1.Id, p.Book2.Id), Math.Max(p.Book1.Id, p.Book2.Id)) ).Select( g => g.First() ).ToList();

我将使用以下

    foreach (var dup in pairs)
    {
        var toRemove = pairs.FirstOrDefault(o => o.Book1.Id == dup.Book2.Id
                                                   && o.Book2.Id == dup.Book1.Id
                                                   && o.Book1.Id > o.Book2.Id);

        if (toRemove != null)
            tempList.Remove(toRemove);
    }

这将专门删除“乱序”的重复项。 但是,如果重复的对具有相同顺序的书籍,则此(和您的原始书籍)将失败。


更好的解决方案(因为我们无论如何都要遍历配对)将使用HashSet

    var hashSet = new HashSet<Tuple<int,int>>();
    foreach (var item in pairs)
    {
        var tuple = new Tuple<int,int>();
        if (item.Book1.Id < item.Book2.Id)
        {
            tuple.Item1 = item.Book1.Id;
            tuple.Item2 = item.Book2.Id;
        }
        else
        {
            tuple.Item1 = item.Book2.Id;
            tuple.Item2 = item.Book1.Id;
        }

        if (hashSet.Contains(tuple))
        {
            tempList.Remove(dup);
        }
        else
        {
            hashSet.Add(tuple);
        }
    }

我设法找到了一种解决方案,但是我不满意。 对于我要完成的工作,它似乎太冗长了。 我现在正在执行其他检查,以查看是否已将重复项添加到列表中:

 if(toRemove != null && tempList.Any(o => o.Book1.Id == toRemove.Book2.Id
                                       && o.Book2.Id == toRemove.Book1.Id))
                                           tempList.Remove(toRemove);

我非常乐意接受其他建议。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM