【问题标题】:Comparing Tuples, Ignoring Order of Elements比较元组,忽略元素的顺序
【发布时间】:2017-06-22 11:25:53
【问题描述】:

假设我有对象 Foo 和 Bar;和 3 个名为 A、B 和 C 的元组。

A = (Foo, Bar)
B = (Bar, Foo)
C = (Foo, Bar)

我想知道它们的元素是否相同,不考虑元素的顺序。所以我想要的结果是;

A.HasSameElementsWith(B)  -> True
A.HasSameElementsWith(C)  -> True
B.HasSameElementsWith(C)  -> True

我知道我可以运行一个嵌套循环来比较它们的每个元素。大致如下:

foreach (itemA in A)
{
    bool flag = false;

    foreach (itemB in B)
    {
        if(itemA == itemB)
        {
            flag = true;
            break;
        }
    }

    if (!flag) return false;
}

return true;

但这似乎效率低下。有没有更方便的方法来做到这一点?


注意:

我使用的是泛型,所以FooBar 可以是任何类型。但它们将是同一类型。 (即Foo的类型将与Bar的类型相同)

【问题讨论】:

  • 排序或查找是加快速度的常用方法
  • @doctorlove 排序也出现在我的脑海中,但是查找是什么意思?如果您能详细说明,我将不胜感激。
  • 你知道你的==只会比较引用而不是相等的
  • @Tim 很抱歉造成混淆。我觉得现在好多了。
  • 根据编程语言中元组的大多数定义,元组是一组有序元素,这意味着你几乎必须自己编写这个比较。

标签: c# .net comparison tuples c#-7.0


【解决方案1】:

如果您有两个 2 元组,那么根据您的规则,只有两个选项可以让它们相等,您可以将其编写为几乎单行的方法:

public static bool HasSameElementsWith<T>(this (T, T) tuple1, (T, T) tuple2) =>
    (Equals(tuple1.Item1, tuple2.Item1) && Equals(tuple1.Item2, tuple2.Item2)) ||
    (Equals(tuple1.Item1, tuple2.Item2) && Equals(tuple1.Item2, tuple2.Item1));

如果每个元组可以有两个以上的项目,那么我会开始将它们视为一个集合,那么问题就变成了两个集合是否具有相同的项目。为此,您可以对Dictionary&lt;T, int&gt; 中的第一个集合中的每个项目进行计数,然后对第二个集合中的项目进行计数。如果两个集合都包含相同的项目,则所有计数最后都应为零。 (如果您确定每个集合中的项目都是唯一的,则可以改用HashSet&lt;T&gt;。)在代码中:

public static bool HasSameElementsWith<T>(
    this IEnumerable<T> collection1, IEnumerable<T> collection2)
{
    var counts = new Dictionary<T, int>();

    foreach (var item in collection1)
    {
        counts.TryGetValue(item, out int count);
        count++;
        counts[item] = count;
    }

    foreach (var item in collection2)
    {
        counts.TryGetValue(item, out int count);
        if (count == 0)
            return false;
        count--;
        counts[item] = count;
    }

    return counts.Values.All(c => c == 0);
}

现在您可以在集合版本之上实现HasSameElementsWith 的元组版本:

public static bool HasSameElementsWith<T>(this (T, T) tuple1, (T, T) tuple2) =>
    HasSameElementsWith(tuple1.ToArray(), tuple2.ToArray());

public static T[] ToArray<T>(this (T, T) tuple) => new[] { tuple.Item1, tuple.Item2 };

【讨论】:

    【解决方案2】:

    我会稍微解释一下@doctorlove 的评论。 他提到了排序。排序后,您可以逐个元素地比较它们。伪代码:

    public bool Compare(A, B){
        return (A[1] == B[1] & A[2] == B[2]);
    }
    

    【讨论】:

      猜你喜欢
      • 2023-03-21
      • 2018-08-16
      • 1970-01-01
      • 2012-10-03
      • 2013-05-08
      • 1970-01-01
      • 2016-08-13
      • 2011-12-27
      • 1970-01-01
      相关资源
      最近更新 更多