0

I have a 2d array of strings:

string[,] arr = new string[3,3]{
  { "a", "b", "c" }, 
  { "a", "b", "c" }, 
  { "d", "e", "f" }, 
}

The result I would like to get is:

a,b,c = 2

d,e,f = 1

I tried:

List<List<string>> lLString = new List<List<string>>();
string[,] stringArray2D = new string[3, 3] {
    { "a", "b", "c" }, 
    { "a", "b", "c" }, 
    { "d", "e", "f" }, 
};
for (int i = 0; i < stringArray2D.GetLength(0); i++) {
    List<string> temp = new List<string>();
    for (int j = 0; j < stringArray2D.GetLength(1); j++) { 
        temp.Add(stringArray2D[i,j]);
    }
    lLString.Add(temp);
}

trying to get it out by doing this :

lLString.GroupBy (ls => ls);

but doesn't seem right

paparazzo
  • 44,497
  • 23
  • 105
  • 176
xaisoft
  • 3,343
  • 8
  • 44
  • 72
  • 1
    So... what have you tried so far? And where exactly are you stuck? – bassfader Jun 20 '18 at 13:01
  • @bassfader - updated – xaisoft Jun 20 '18 at 13:02
  • 1
    Linq isn't compatible with multidimensional arrays. You chose the wrong instrument (multidimensional arrays) for your work. Not that with jagged arrays it would be easy (you would need an ArrayComparer) – xanatos Jun 20 '18 at 13:06
  • @xaisoft: You say "I tried", but the posted code does not show an attempt at grouping. You converted the multidimensional array to a jagged array (jagged _list_, I guess...), but you haven't actually tried to group them. – Flater Jun 20 '18 at 13:12
  • @Flater - I thought by converting it to a list first, I could call the groupby on it. – xaisoft Jun 20 '18 at 13:13
  • 1
    I think you would need to crate a class to hold the list that implement iequatable – paparazzo Jun 20 '18 at 13:19
  • No IDE but with a fucntion like this `IEnumerable SelectRow(this T[,] inputArray, int index){ for(int i = inputArray.GetLowerBound(1); i <= inputArray.GetUpperBound(1); ++i) yield return inputArray[index, i]; }`, you select each row and group them. A lazy trick would be to concatenate by chunk that have the size of a row. 1 row into a big string – Drag and Drop Jun 20 '18 at 13:28

3 Answers3

2

You could have used directly a jagged array, like:

string[][] arrayJagged = new[]
{
    new[] { "a", "b", "c" },
    new[] { "a", "b", "c" },
    new[] { "d", "e", "f" },
    new[] { "g", "h", "i" },
};

but you want to dig in the ruins of the past and use multidimensional array, just to make everything more complex.

string[,] stringArray2D = new string[,] 
{
    { "a", "b", "c" },
    { "a", "b", "c" },
    { "d", "e", "f" },
    { "g", "h", "i" },
};

Then we will have to convert the multidimensional array to a jagged array:

string[][] arrayJagged = new string[stringArray2D.GetLength(0)][];

int length2 = stringArray2D.GetLength(1);

for (int i = 0; i < arrayJagged.Length; i++)
{
    arrayJagged[i] = new string[length2];

    for (int j = 0; j < length2; j++)
    {
        arrayJagged[i][j] = stringArray2D[i, j];
    }
}

Note that you don't really need a List<List<string>> because in the end the dimensions of the jagged array are predetermined.

Then you can .GroupBy() the jagged array, and do a .Count() on each group:

var grouped = arrayJagged.GroupBy(x => x, ArrayEqualityComparer<string>.Default)
    .Select(x => new
    {
        x.Key,
        Count = x.Count()
    })
    .ToArray();

Note that .NET doesn't have a default equality comparer for arrays, so you'll need to define one, to show the .GroupBy() how to check for equality of elements:

// Simple T[] IEqualityComparer<>
public sealed class ArrayEqualityComparer<T> : IEqualityComparer<T[]>, IEqualityComparer
{
    // One instance is more than enough
    public static readonly ArrayEqualityComparer<T> Default = new ArrayEqualityComparer<T>();

    // We lazily define it if necessary
    private readonly IEqualityComparer<T> equalityComparer;

    public ArrayEqualityComparer()
    {
        equalityComparer = EqualityComparer<T>.Default;
    }

    public ArrayEqualityComparer(IEqualityComparer<T> equalityComparer)
    {
        this.equalityComparer = equalityComparer;
    }

    /* IEqualityComparer<T[]> */

    public bool Equals(T[] x, T[] y)
    {
        if (x == null)
        {
            if (y == null)
            {
                return true;
            }

            return false;
        }

        if (y == null)
        {
            return false;
        }

        return EqualsNotNull(x, y);
    }

    public int GetHashCode(T[] obj)
    {
        unchecked
        {
            int hash = 17;

            if (obj != null)
            {
                // This one will help distinguish between null and empty:
                // hash(null) == 17, hash(empty) == 17 * 23
                hash = (hash * 23) + obj.Length;

                for (int i = 0; i < obj.Length; i++)
                {
                    hash = (hash * 23) + obj[i].GetHashCode();
                }
            }

            return hash;
        }
    }

    /* IEqualityComparer */

    bool IEqualityComparer.Equals(object x, object y)
    {
        if (x == y)
        {
            return true;
        }

        if (x == null || y == null)
        {
            return false;
        }

        var x2 = x as T[];

        if (x2 == null)
        {
            throw new ArgumentException("x");
        }

        var y2 = y as T[];

        if (y2 == null)
        {
            throw new ArgumentException("y");
        }

        return EqualsNotNull(x2, y2);
    }

    int IEqualityComparer.GetHashCode(object obj)
    {
        T[] obj2;

        if (obj != null)
        {
            obj2 = obj as T[];

            if (obj2 == null)
            {
                throw new ArgumentException("obj");
            }
        }
        else
        {
            obj2 = null;
        }

        return GetHashCode(obj2);
    }

    /* Implementation */

    private bool EqualsNotNull(T[] x, T[] y)
    {
        if (x.Length != y.Length)
        {
            return false;
        }

        if (x.Length != 0)
        {
            for (int i = 0; i < x.Length; i++)
            {
                if (!equalityComparer.Equals(x[i], y[i]))
                {
                    return false;
                }
            }
        }

        return true;
    }
}
xanatos
  • 109,618
  • 12
  • 197
  • 280
1

Create a class the overrides equals

public static void GroupList()
{
    List<ListComp> lLString = new List<ListComp>();
    string[,] stringArray2D = new string[3, 3] { { "a", "b", "c" },
                                                 { "a", "b", "c" },
                                                 { "d", "e", "f" },
                                                };
    for (int i = 0; i<stringArray2D.GetLength(0); i++) {
        ListComp temp = new ListComp();
        for (int j = 0; j<stringArray2D.GetLength(1); j++) { 
            temp.Add(stringArray2D[i, j]);
        }
        lLString.Add(temp);
    }
    var gr = lLString.GroupBy(i => i);

    foreach (var g in gr)
    {
        Debug.WriteLine($"{g.Key} = {g.Count()}");
    }
    Debug.WriteLine("");
}
public class ListComp : List<string>
{
    public override string ToString()
    {
        return string.Join(",", this);
    }
    public override bool Equals(object obj)
    {
        ListComp listComp = obj as ListComp;
        if (listComp == null)
            return false;
        else
            return Equals(listComp);
    }
    public bool Equals(ListComp listComp)
    {
        if (listComp == null)
            return false;

        return this.SequenceEqual(listComp);
    }
    public override int GetHashCode()
    {
        int hash = 1;
        foreach(string s in this)
        {
            hash *= s.GetHashCode();
        }
        return hash;
    }
    public ListComp (List<string> listComp)
    {
        this.AddRange(listComp);
    }
    public ListComp()
    {
    }
}
paparazzo
  • 44,497
  • 23
  • 105
  • 176
0

Using a basic for loops similar to the one you used create a list of strings. Then use the GroupBy.

string[,] arr = new string[3, 3]
{
        { "a", "b", "c" },
        { "a", "b", "c" },
        { "d", "e", "f" },
};

int dim1 = arr.GetLength(0);
int dim2 = arr.GetLength(1);

List<string> temp = new List<string>();
string st;
for (int i = 0; i < dim1; i++)
{
    st = "";
    for (int j = 0; j < dim2; j++)
        st += arr[i, j] + ",";
    temp.Add(st);
}

var gr = temp.GroupBy(i => i);

foreach (var g in gr)
    Console.WriteLine($"{g.Key} = {g.Count()}");

Output: a,b,c, = 2 d,e,f, = 1

L_J
  • 2,351
  • 10
  • 23
  • 28