如何删除C#元组列表中的反向重复项

如何删除C#元组列表中的反向重复项,c#,asp.net,tuples,C#,Asp.net,Tuples,假设我有这样一个元组列表: List<Tuple<string, string>> conflicts = new List<Tuple<string, string>>(); conflicts.Add(new Tuple<string, string>("Maths", "English")); conflicts.Add(new Tuple<string, string>("Science",

假设我有这样一个元组列表:

    List<Tuple<string, string>> conflicts = new List<Tuple<string, string>>();
    conflicts.Add(new Tuple<string, string>("Maths", "English"));
    conflicts.Add(new Tuple<string, string>("Science", "French"));
    conflicts.Add(new Tuple<string, string>("French", "Science"));
    conflicts.Add(new Tuple<string, string>("English", "Maths"));
var noConflicts = conflicts.Select(t =>
    String.CompareOrdinal(t.Item1, t.Item2) > 0 ? new Tuple<string, string>(t.Item2, t.Item1) : t
    ).Distinct();
列表冲突=新建列表();
添加(新元组(“数学”、“英语”);
添加(新元组(“科学”、“法语”);
添加(新元组(“法语”、“科学”);
添加(新元组(“英语”、“数学”));
我想检查元组列表中的反向重复项并将其删除,我该如何使用循环来实现这一点

注:反向重复指“英语”、“数学”和“数学”、“英语”的重复出现

注意:我的代码中的元组是使用SqlDataReader填充的,但是我上面使用的示例非常接近它的布局方式


这看起来很简单,但它整晚都被难住了

问题是你误用了
元组
。如果
{“数学”、“科学”}
{“科学”、“数学”}
是可互换的,那么它们不是成对的。您更多地将其用作
字符串[2]
。例如,在
字典
中,这是一个
元组
,它们是有意义的独立事物,具有适当的对关系,而不仅仅是数据列表


尝试使用类似于
List
的工具,它可以更好地表示您的数据,并允许您访问有用的
List
答案,如。或者实际上是
列表
,其中
冲突
包含一个
列表
,其中顺序对于平等并不重要

一个相当粗糙的实现:

var distinct =
    conflicts
        .GroupBy(
            x =>
                {
                    var ordered = new[] { x.Item1, x.Item2 }.OrderBy(i => i);
                    return
                        new
                        {
                            Item1 = ordered.First(),
                            Item2 = ordered.Last(),
                        };
                })
        .Distinct()
        .Select(g => g.First())
        .Dump();
它对元组中的项进行排序,使Math、English和Engilsh、Math相同,然后将它们放入一个匿名类型(再次调用things Item1/2),然后依赖匿名类型的结构相等性来执行不同的操作,然后我只需从每个组中取出第一个元组。

List conflicts=new List();
List<Tuple<string, string>> conflicts = new List<Tuple<string, string>>();
List<Tuple<string, string>> noConflicts = new List<Tuple<string, string>>();

conflicts.Add(new Tuple<string, string>("Maths", "English"));
conflicts.Add(new Tuple<string, string>("Science", "French"));
conflicts.Add(new Tuple<string, string>("French", "Science"));
conflicts.Add(new Tuple<string, string>("English", "Maths"));

foreach(Tuple<string,string> t in conflicts)
{
      if(!noConflicts.Contains(t) && !noConflicts.Contains(new Tuple<string,string>(t.Item2,t.Item1)))
           noConflicts.Add(t);
}

foreach(Tuple<string, string> t in noConflicts)
       Console.WriteLine(t.Item1 + "," + t.Item2);
List noConflicts=新列表(); 添加(新元组(“数学”、“英语”); 添加(新元组(“科学”、“法语”); 添加(新元组(“法语”、“科学”); 添加(新元组(“英语”、“数学”)); foreach(冲突中的元组t) { 如果(!noConflicts.Contains(t)&&!noConflicts.Contains(新元组(t.Item2,t.Item1))) 无冲突。添加(t); } foreach(无冲突中的元组t) 控制台写入线(t.Item1+“,”+t.Item2);
我相信有更好的方法,但它是有效的

使用系统;
使用System.Collections.Generic;
使用System.Linq;
公共课程
{
公共静态void Main()
{
var conflicts=新列表();
添加(新元组(“数学”、“英语”);
添加(新元组(“科学”、“法语”);
添加(新元组(“法语”、“科学”);
添加(新元组(“英语”、“数学”));
清除(冲突);
foreach(冲突中的变量i)Console.WriteLine(i.Item1+“”+i.Item2);
}
公共静态void RemoveDupes(列表集合){
var duplicates=collection
//无法描述哪个值首先出现
.Select((x,i)=>new{Item=new Tuple(x.Item2.isgreater大于(x.Item1)?x.Item2:x.Item1,
x、 Item2.IsGreaterThan(x.Item1)?x.Item1:x.Item2,Index=i})
//现在无法形容的价值观群体
.GroupBy(x=>x.Item)
//查找重复项
.Where(x=>x.Count()>1)
.Select(x=>new{Items=x,Count=x.Count()})
//选择除第一个之外的所有索引
.SelectMany(x=>
x、 Items.Select(b=>b)
.Zip(可枚举范围(1,x.计数),
(j,i)=>new{Item=j,RowNumber=i}
)
)。其中(x=>x.RowNumber!=1);
foreach(重复的var项目){
collection.RemoveAt(item.item.Index);
}
}
}
公共静态类Ext{
公共静态布尔值大于(此字符串val,字符串比较){
返回val.CompareTo(比较)==1;
}
}

带有自定义的
IEqualityComparer

public class TupleComparer : IEqualityComparer<Tuple<string, string>>
{
    public bool Equals(Tuple<string, string> x, Tuple<string, string> y)
    {
        return  (x.Item1 == y.Item1 && x.Item2 == y.Item2) ||
                (x.Item1 == y.Item2 && x.Item2 == y.Item1);
    }

    public int GetHashCode(Tuple<string, string> obj)
    {
        return string.Concat(new string[] { obj.Item1, obj.Item2 }.OrderBy(x => x)).GetHashCode();
        //or
        //return (string.Compare(obj.Item1, obj.Item2) < 0 ? obj.Item1 + obj.Item2 : obj.Item2 + obj.Item1).GetHashCode(); 
    }
}
公共类TupleComparer:IEqualityComparer
{
公共布尔等于(元组x,元组y)
{
返回(x.Item1==y.Item1&&x.Item2==y.Item2)||
(x.Item1==y.Item2&&x.Item2==y.Item1);
}
public int GetHashCode(元组对象)
{
返回string.Concat(新字符串[]{obj.Item1,obj.Item2}.OrderBy(x=>x)).GetHashCode();
//或
//返回(string.Compare(obj.Item1,obj.Item2)<0?obj.Item1+obj.Item2:obj.Item2+obj.Item1).GetHashCode();
}
}
您可以使用
HashSet
而不是
List

var conflicts=newhashset(new TupleComparer());
添加(新元组(“数学”、“英语”);
添加(新元组(“科学”、“法语”);
添加(新元组(“法语”、“科学”);
添加(新元组(“英语”、“数学”));

LINQ一行。一定会喜欢的

var noConflicts = conflicts.Select(c => new HashSet<string>() { c.Item1, c.Item2})
    .Distinct(HashSet<string>.CreateSetComparer())
    .Select(h => new Tuple<string, string>(h.First(), h.Last()));
var noConflicts=conflicts.Select(c=>newhashset(){c.Item1,c.Item2})
.Distinct(HashSet.CreateSetComparer())
.Select(h=>newtuple(h.First(),h.Last());

这是通过将所有内容发送到一个
HashSet
,该HashSet具有
CreateSetComparer()
方法,该方法允许它执行
Distinct()
,而不考虑顺序

避免AB/BA表示不明确的最佳方法是使用数据模型,这不允许使用它们。通过施加约束,您可以实现这一点,在数据库中,这是一种广泛使用的方法。如果我们说元组是有序的,那么就不会出现歧义

public class Ordered2StrTuple : Tuple<string, string> 
{
    public Ordered2StrTuple(string a, string b)
        : this(a, b, String.CompareOrdinal(a,b))
    { }

    private Ordered2StrTuple(string a, string b, int cmp)
        : base(cmp > 0 ? b : a, cmp > 0 ? a : b)
    { }
}
为了与Equal保持一致,比较必须是有序的,所以我删除了这里的通用版本。如果您只想执行一次重复数据消除,可以按如下方式执行:

    List<Tuple<string, string>> conflicts = new List<Tuple<string, string>>();
    conflicts.Add(new Tuple<string, string>("Maths", "English"));
    conflicts.Add(new Tuple<string, string>("Science", "French"));
    conflicts.Add(new Tuple<string, string>("French", "Science"));
    conflicts.Add(new Tuple<string, string>("English", "Maths"));
var noConflicts = conflicts.Select(t =>
    String.CompareOrdinal(t.Item1, t.Item2) > 0 ? new Tuple<string, string>(t.Item2, t.Item1) : t
    ).Distinct();
var noConflicts=冲突。选择(t=>
String.CompareOrdinal(t.Item1,t.Item2)>0?新元组(t.Item2,t.Item1):t
).Distinct();

要同时删除这两个副本,还是删除lea
var noConflicts = conflicts.Select(t =>
    String.CompareOrdinal(t.Item1, t.Item2) > 0 ? new Tuple<string, string>(t.Item2, t.Item1) : t
    ).Distinct();