【问题标题】:Storing pair of ints on the list在列表中存储一对整数
【发布时间】:2011-05-20 06:27:27
【问题描述】:

如何在列表中存储整数对? 我知道我可以为他们开设一堂课,例如:

class Pair  
{
    int i1,i2;
}

但如果我这样做,我将无法使用Contains 函数来检查给定对是否在列表中。我该怎么做才能轻松地将整数存储在 List 中并检查一对整数是否已经存在?我不能使用表格,因为不知道会有多少对。

编辑:
忘了补充: 在我的程序对 (x, y) 和 (y, x) 将被视为平等。

编辑:
(x,y) 和 (y,x) 在检查Point 是否在列表中时相等,但xy 不能交换,因为xy 表示两点之间的连接(整数是点的 id,不,我不能使用任何参考等......)。当我检查 List 是否包含连接时,它是 (x,y) 还是 (y,x) 并不重要,但稍后我需要该信息。

【问题讨论】:

    标签: c# list integer


    【解决方案1】:

    如果您使用的是 .NET 4.0,则可以使用 Tuple 类,如

    var tuple = new Tuple<int, int>(17, 42);
    var otherTuple = Tuple.Create(17, 42);
    

    var list = new List<Tuple<int, int>>();
    

    请注意,如果您使用Tuple&lt;int, int&gt;,那么您将需要创建IEqualityComparer&lt;Tuple&lt;TFirst, TSecond&gt;&gt; 的自定义实现,以反映(x, y) 被视为等于(y, x) 的相等规则。然后,您必须将此比较器的一个实例传递给List&lt;T&gt;.Contains(T, IEqualityComparer&lt;T&gt;)(这里TTuple&lt;int, int&gt;)。

    class TupleAsUnorderedPairComparer : IEqualityComparer<Tuple<TFirst, TSecond>> {
        public bool Equals(Tuple<TFirst, TSecond> x, Tuple<TFirst, TSecond> y) {
            if(Object.ReferenceEquals(x, y)) {
                return true;
            }
            if(x == null || y == null) {
                return false;
            }
            return x.Item1 == y.Item1 && x.Item2 == y.Item2 ||
                   x.Item1 == y.Item2 && x.Item2 == y.Item1;
        }
    
        public int GetHashCode(Tuple<TFirst, TSecond> x) {
            if(x == null) {
                return 0;
            }
            return x.Item1.GetHashCode() ^ x.Item2.GetHashCode();
        }
    }
    

    否则,如果您不能或不想使用Tuple,那么您将需要为您的Pair 类实现IEqualityComparer&lt;Pair&gt; 或覆盖Object.EqualsObject.GetHashCode

    class Pair {
        public int First { get; private set; }
        public int Second { get; private set; }
        public Pair(int first, int second) {
            this.First = first;
            this.Second = second;
        }
    
        public override bool Equals(object obj) {
            if(Object.ReferenceEquals(this, obj)) {
                return true;
            }
            Pair instance = obj as Pair;
            if(instance == null) {
                return false;
            }
            return this.First == instance.First && this.Second == instance.Second ||
                   this.First == instance.Second && this.Second == instance.First;
        }
    
        public override int GetHashCode() {
            return this.First.GetHashCode() ^ this.Second.GetHashCode();
        }
    }
    

    class PairEqualityComparer : IEqualityComparer<Pair> {
        // details elided 
    }
    

    如果你使用

    list.Contains(pair);
    

    那么它将使用EqualsGetHashCode 但如果你使用

    list.Contains(pair, new PairEqualityComparer);
    

    那么它将使用PairEqualityComparer.EqualsPairEqualityComparer.GetHashCode。请注意,这些可能不同于您的 Object.EqualsObject.GetHashCode 的实现。

    最后,如果你会经常进行收容测试,那么List 不是你最好的选择;您应该使用为此目的设计的类,例如 HashSet

    【讨论】:

    • 我已经编辑了我的答案,以反映您需要将 (x, y) 视为等于 (y, x)
    【解决方案2】:

    课程是您最好的选择。如果你死心塌地使用Contains 方法,你必须在你的Pair 类中实现IComparable 接口。这将允许您确定这对整数的“相等”意味着什么。

    最简单的方法是按照您的方式创建类,然后在 List&lt;T&gt; 对象上创建和扩展方法。

    public static bool ContainsIntegers(this List<Pair> targetList, Pair comparer) {
        foreach(Pair pair in targetList)
        {
            if(pair.i1 == comparer.i1 && pair.i2 == comparer.i2) return true;
        }
        return false;
    }
    

    【讨论】:

      【解决方案3】:

      另一种方法是使用List&lt;ulong&gt;,将最大的数字放在高32位,另一个数字放在低32位:

      ulong MakeEntry(int i1, int i2)
      {
          ulong hi = (ulong)Math.Max(i1, i2);
          ulong lo = (ulong)Math.Min(i1, i2);
          return (hi << 32) | lo;
      }
      
      List<ulong> items = new List<ulong>();
      
      void DoSomething()
      {
          // get numbers i1 and i2
          // and add to the list
          items.Add(MakeEntry(i1, i2));
      
          // test to see if the pair is in the list
          if (items.Contains(MakeEntry(i1, i2)))
          {
              // do whatever
          }
      }
      

      【讨论】:

      • 这不起作用,因为要求(x, y) 被视为等于(y, x)。也就是说,OP 使用的是 unordered 对,而不是 ordered 对。
      • @Jason:嗯? MakeEntry 方法中的最小值/最大值确保 (x, y) 和 (y, x) 被同等对待。最大的总是在高位。
      • 虽然此解决方案将 (x,y) 视为等于 (y,x),但它通过交换两个值来实现。我不清楚 OP 是否希望 i1 和 i2 可以单独访问。如果是这样,此解决方案将不起作用。
      猜你喜欢
      • 1970-01-01
      • 2020-11-01
      • 2013-11-09
      • 2018-09-23
      • 1970-01-01
      • 2014-05-23
      • 2012-10-08
      • 1970-01-01
      相关资源
      最近更新 更多