【问题标题】:How to do a job ForEach element of 2d array without For loop?如何在没有 For 循环的情况下完成二维数组的 ForEach 元素的工作?
【发布时间】:2016-04-17 11:58:28
【问题描述】:

我需要知道如何在没有 For 循环的情况下修改或初始化二维数组的所有元素?
我的意思是如何使用扩展方法或使用 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";
        }

但是请忘记这个 for 循环!
只需尝试使用一行表达式即可!
像这个不起作用的...

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

谢谢!

【问题讨论】:

  • “如何使用扩展方法来做到这一点”——好吧,怎么样:public static class ArrayExtensions { public static void SetAllValuesTo(this string[,] array, string value) { for (var i = 0; i &lt; array.GetLength(0); i++) { for (var j = 0; j &lt; array.GetLength(1); j++) { array[i, j] = value; } } } }?然后将其称为array.SetAllValuesTo("sample");

标签: c# arrays linq multidimensional-array ienumerable


【解决方案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"));

【讨论】:

    【解决方案2】:

    虽然@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

    由于需要存储每个项目的索引,效率不高,但对于一些极少数情况,它仍然是一种可能的解决方案。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-01-12
      • 2021-05-13
      • 1970-01-01
      • 2018-08-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多