从字符串数组中删除重复项

时间:2011-09-25 08:52:17

标签: c# arrays

我是C#的新手,看过很多帖子但我仍感到困惑。

我有一个数组列表:

List<Array> moves = new List<Array>();

我正在使用以下内容添加移动:

string[] newmove = { piece, axis.ToString(), direction.ToString() };
moves.Add(newmove);

现在我希望使用以下内容删除重复项:

moves = moves.Distinct();

然而,这不是让我这样做的。我收到这个错误:

无法将类型'System.Collections.Generic.IEnumerable'隐式转换为'System.Collections.Generic.List'。存在显式转换(您是否错过了演员?)

请帮忙吗?我会非常感激。

史蒂夫

4 个答案:

答案 0 :(得分:3)

您需要在.ToList()方法后调用.Distinct,因为它返回IEnumerable<T>。我还建议您使用强类型List<string[]>代替List<Array>

List<string[]> moves = new List<string[]>();
string[] newmove = { piece, axis.ToString(), direction.ToString() };
moves.Add(newmove);
moves.Add(newmove);

moves = moves.Distinct().ToList();
// At this stage moves.Count = 1

答案 1 :(得分:3)

您的代码有两个错误。第一个是对ToList的遗失调用,正如已经指出的那样。第二是微妙的。 Unique按标识比较对象,但重复的列表项具有不同的数组实例。

这个问题有多种解决方案。

  • moves.Distinct().ToList()中使用自定义相等比较器。无需进一步更改。

    示例实施:

    class ArrayEqualityComparer<T> : EqualityComparer<T> {
        public override bool Equals(T[] x, T[] y) {
            if ( x == null ) return y == null;
            else if ( y == null ) return false;
            return x.SequenceEquals(y);
        }
        public override int GetHashCode(T[] obj) {
            if ( obj == null) return 0;
            return obj.Aggregate(0, (hash, x) => hash ^ x.GetHashCode());
        }
    }
    

    过滤唯一商品:

    moves = moves.Distinct(new ArrayEqualityComparer<string>()).ToList();
    
  • 使用元组<string,string,string>代替string[]。元组提供内置的结构平等和比较。由于长类型名称,此变体可能会使您的代码混乱。

    实例化:

    List<Tuple<string, string, string>> moves = 
        new List<Tuple<string, string, string>>();
    

    添加新动作:

    Tuple<string, string, string> newmove = 
        Tuple.Create(piece, axis.ToString(), direction.ToString()); 
    moves.Add(newmove);
    

    过滤唯一商品:

    moves = moves.Distinct().ToList();
    
  • 使用自定义类来保存您的三个值。我实际上推荐这个变种,因为它使你处理动作的所有代码更具可读性。

    示例实施:

    class Move {
    
        public Move(string piece, string axis, string direction) {
            Piece = piece;
            Axis = axis;
            Direction = direction;
        }
    
        string Piece { get; private set; }
        string Axis { get; private set; }
        string Direction { get; private set; }
    
        public override Equals(object obj) {
            Move other = obj as Move;
            if ( other != null ) 
                return Piece == other.Piece && 
                       Axis == other.Axis && 
                       Direction == other.Direction;
            return false;
        }
    
        public override GetHashCode() {
            return Piece.GetHashCode() ^ 
                   Axis.GetHashCode() ^ 
                   Direction.GetHashCode();
        }
    
        // TODO: override ToString() as well
    }
    

    实例化:

    List<Move> moves = new List<Move>();
    

    添加新动作:

    Move newmove = new Move(piece, axis.ToString(), direction.ToString()); 
    moves.Add(newmove);
    

    过滤唯一商品:

    moves = moves.Distinct().ToList();
    

答案 2 :(得分:2)

编译错误是因为您需要将结果转换为列表:

moves = moves.Distinct().ToList();

然而,它可能无法正常工作,因为数组没有以您希望的方式定义Equals(它比较数组对象的引用,而不是数组中的值) 。不要使用数组,而是创建一个类来保存数据,并定义EqualsGetHashCode来比较值。

答案 3 :(得分:0)

老问题,但这是使用O(1)额外空间的O(n)解决方案:

public static void RemoveDuplicates(string[] array)
    {
        int c = 0;
        int i = -1;

        for (int n = 1; n < array.Length; n++)
        {
            if (array[c] == array[n])
            {
                if (i == -1)
                {
                    i = n;
                }
            }
            else
            {
                if (i == -1)
                {
                    c++;
                }
                else
                {
                    array[i] = array[n];
                    c++;
                    i++;
                }
            }
        }
    }