如何做一个没有For循环的2d数组的ForEach元素?

时间:2016-04-17 11:58:29

标签: c# arrays linq multidimensional-array ienumerable

我需要知道如何修改或如何在没有For循环的情况下初始化2d数组的所有元素?
我是指如何使用Extension方法或使用LINQ来做到这一点!?

我试图使用“IEnumerable.Cast<>”来做延期,但没有结果!
而且我不知道为什么?

        string[,] m2d = new string[8, 8];

        Array.ForEach(m2d.Cast<string>().ToArray(), el => el = "sample1");

即使使用for循环也没有结果...

        for (int i = 0; i <= m2d.Cast<string>().ToArray().GetUpperBound(0); i++)
        {
            m2d.Cast<string>().ToArray()[i] = "sample2";
        }

但请忘记这个循环!
试着用一行表达式来做! 像这个不起作用......

        m2d.Cast<string>().ToList().ForEach(el => el = "sample3");

谢谢!

2 个答案:

答案 0 :(得分:1)

它不起作用,因为通过赋值,您只需将ToList()ToArray()方法创建的集合中的值替换为新值。因为这两种方法实际上都返回了新的集合,所以您的起始数组不会受到您所做的更改的影响。

当然,最明显的方法是使用两个嵌套的for循环。不确定为什么要避免使用它们但是如果你真的想使用ForEach,你可以枚举数组维度的索引,而不是它的元素,就像功能方法一样。像这样:

Enumerable.Range(0, m2d.GetUpperBound(0) + 1).ToList()
            .ForEach(i => Enumerable.Range(0, m2d.GetUpperBound(1) + 1).ToList()
                .ForEach(j => m2d[i, j] = "sample"));

答案 1 :(得分:0)

虽然@Dmitry的答案几乎涵盖了why the original attempt has failed以及你应该做些什么来纠正,但是,根据你的要求,你可能还想考虑将数组中的每个项目/索引包装成一些参考类型,能够更改原始数组项:

public class MultiDimensionArrayItemReference<T>
{
    private readonly Array _array;
    private readonly Int32[] _indices;

    public MultiDimensionArrayItemReference(Array array, params Int32[] indices)
    {
        if (array == null)
            throw new ArgumentNullException(paramName: nameof(array));
        if (indices == null)
            throw new ArgumentNullException(paramName: nameof(indices));
        this._array = array;
        this._indices = indices;
    }

    public IReadOnlyCollection<Int32> Indices
    {
        get
        {
            return this._indices.ToList().AsReadOnly();
        }
    }

    public T Value
    {
        get
        {
            return (T)this._array.GetValue(this._indices);
        }
        set
        {
            this._array.SetValue(value, this._indices);
        }
    }

    public override string ToString()
    {
        return $"[{String.Join(", ", this._indices)}]:{this.Value}";
    }
}


public static class MultiDimensionArrayItemReferenceExtensions
{
    // That's for the two-dimensional array, but with some effort it can be generalized to support any arrays.
    public static IEnumerable<MultiDimensionArrayItemReference<T>> EnumerateReferenceElements<T>(this T[,] array)
    {
        if (array == null)
            throw new ArgumentNullException(paramName: nameof(array));

        // Assume zero-based
        var rows = array.GetLength(0);
        var columns = array.GetLength(1);

        for (int row = 0; row < rows; row++)
        { 
            for (int col = 0; col < columns; col++)
            {
                yield return new MultiDimensionArrayItemReference<T>(
                    array,
                    row,
                    col);
            }
        }
    }
}

...

private static void PrintArray<T>(T[,] array)
{
    // Assume zero-based
    var rows = array.GetLength(0);
    var columns = array.GetLength(1);

    for (int row = 0; row < rows; row++)
    {
        for (int col = 0; col < columns; col++)
        {
            Console.Write("{0, 7}", array[row, col]);
        }
        Console.WriteLine();
    }
}

...

var array = new [,]
{
    { "a1", "a2" },
    { "b1", "b2" }
};

PrintArray(array);
Console.WriteLine();

var elements = array
    .EnumerateReferenceElements()
    .ToList();

foreach (var elem in elements)
{
    Console.WriteLine(elem);
}

elements.ForEach(
    elem =>
        elem.Value = elem.Value + "_n");

Console.WriteLine();
PrintArray(array);

将产生以下输出:

     a1     a2
     b1     b2

[0, 0]:a1
[0, 1]:a2
[1, 0]:b1
[1, 1]:b2

   a1_n   a2_n
   b1_n   b2_n

由于需要存储每个项目的索引,因此效率不高,但对于一些罕见的情况仍然是可能的解决方案。