Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Removing duplicates from string array

Tags:

arrays

c#

I'm new to C#, have looked at numerous posts but am still confused.

I have a array list:

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

I'm adding moves to it using the following:

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

And now I wish to remove duplicates using the following:

moves = moves.Distinct();

However it's not letting me do it. I get this error:

Cannot implicitly convert type 'System.Collections.Generic.IEnumerable' to 'System.Collections.Generic.List'. An explicit conversion exists (are you missing a cast?)

Help please? I'd be so grateful.

Steve

like image 478
Steve Gore Avatar asked Feb 23 '23 21:02

Steve Gore


2 Answers

You need to call .ToList() after the .Distinct method as it returns IEnumerable<T>. I would also recommend you using a strongly typed List<string[]> instead of 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
like image 197
Darin Dimitrov Avatar answered Mar 08 '23 13:03

Darin Dimitrov


Your code has two errors. The first is the missing call to ToList, as already pointed out. The second is subtle. Unique compares objects by identity, but your duplicate list items have are different array instances.

There are multiple solutions for that problem.

  • Use a custom equality comparer in moves.Distinct().ToList(). No further changes necessary.

    Sample implementation:

    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());
        }
    }
    

    Filtering for unique items:

    moves = moves.Distinct(new ArrayEqualityComparer<string>()).ToList();
    
  • Use Tuple<string,string,string> instead of string[]. Tuple offers built-in structural equality and comparison. This variant might make your code cluttered because of the long type name.

    Instantiation:

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

    Adding new moves:

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

    Filtering for unique items:

    moves = moves.Distinct().ToList();
    
  • Use a custom class to hold your three values. I'd actually recommend this variant, because it makes all your code dealing with moves much more readable.

    Sample implementation:

    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
    }
    

    Instantiation:

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

    Adding new moves:

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

    Filtering for unique items:

    moves = moves.Distinct().ToList();
    
like image 45
Mark Avatar answered Mar 08 '23 12:03

Mark