在C#中将2D数组分组?

时间:2018-06-20 12:58:43

标签: c# arrays

我有一个二维的字符串数组:

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

我想要得到的结果是:

a,b,c = 2

d,e,f = 1

我尝试过:

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

尝试通过以下操作将其删除:

lLString.GroupBy (ls => ls);

但似乎不正确

3 个答案:

答案 0 :(得分:2)

您本可以直接使用锯齿状的数组,例如:

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

但是您想挖掘过去的废墟并使用多维数组,只是使一切变得更加复杂。

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

然后,我们将不得不将多维数组转换为锯齿数组:

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];
    }
}

请注意,实际上并不需要List<List<string>>,因为最后锯齿状数组的尺寸是预先确定的。

然后,您可以.GroupBy()锯齿状的数组,并在每个组上执行.Count()

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

请注意,.NET没有默认的数组相等比较器,因此您需要定义一个数组,以向.GroupBy()展示如何检查元素是否相等:

// 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;
    }
}

答案 1 :(得分:0)

使用类似于您所使用的for循环的基本循环来创建字符串列表。然后使用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()}");

输出: a,b,c, = 2 d,e,f, = 1

答案 2 :(得分:0)

创建一个覆盖等于

的类
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()
    {
    }
}