删除';重复';从配对列表中选择
本文关键字:列表 选择 重复 删除 | 更新日期: 2023-09-27 18:20:47
标题可能会产生误导,因此举个例子:
我有一门课:
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);
我对其他建议持开放态度。