映射多维数组

时间:2018-01-16 20:41:55

标签: c# arrays linq multidimensional-array

我有以下课程

class Tile
{
    public int height;
    public int terrain;
}

我有一个Tiles的二维数组

Tile[,] area = new Tile[5,5];

如何将我的区域从Tile[,]映射到int[,],只保存高度?

我试过这样做:

area.Select(tile => tile.height)

但显然C#多维数组没有实现IEnumerable。

我怎么能解决这个问题?

4 个答案:

答案 0 :(得分:6)

  

我怎么能解决这个问题?

通过编写代码。没有“选择”可行,所以自己做:

static class Extensions 
{
  public static R[,] Select<T, R>(this T[,] items, Func<T, R> f) 
  {
    int d0 = items.GetLength(0);
    int d1 = items.GetLength(1);
    R[,] result = new R[d0, d1];
    for (int i0 = 0; i0 < d0; i0 += 1)
      for (int i1 = 0; i1 < d1; i1 += 1)
        result[i0, i1] = f(items[i0, i1]);
    return result;
  }

现在你有了你想要的扩展方法。

练习:

  • 哪个标准LINQ序列运算符适合多维数组,哪些不适应?
  • 您是否希望在多维数组上看到不是标准LINQ运算符但可以作为扩展方法实现的运算符?

答案 1 :(得分:1)

如果你真的,实际上,只是想要,你可以构建这样的东西:

public static void Main(string[] args)
{
    var area = new Tile[5, 5];

    for (var j = 0; j < 5; j++)
        for (var i = 0; i < 5; i++)
            area[i, j] = new Tile() { height = (j + 1) * (i + 1), terrain = 99 };

你的linq:

    // this copies the data over from your area-array into a new int[5,5] array using
    // IEnumerable.Aggregate(...) with an emtpy seeded int[5,5] array and
    // leverages Enumerable.Range() with integer division + modular to get
    // the indices right

    var onlyHeights = Enumerable
        .Range(0, 25)
        .Aggregate(new int[5, 5], (acc, i) =>
    {
        acc[i / 5, i % 5] = area[i / 5, i % 5].height;
        return acc;
    });

测试:

    for (var j = 0; j < 5; j++)
        for (var i = 0; i < 5; i++)
            Console.WriteLine($"area.height {area[i, j].height} => {onlyHeights[i, j]}");
    Console.ReadLine();
}

输出:

area.height 1 => 1
area.height 2 => 2
area.height 3 => 3
area.height 4 => 4
area.height 5 => 5
area.height 2 => 2
area.height 4 => 4
area.height 6 => 6
area.height 8 => 8
area.height 10 => 10
area.height 3 => 3
area.height 6 => 6
area.height 9 => 9
area.height 12 => 12
area.height 15 => 15
area.height 4 => 4
area.height 8 => 8
area.height 12 => 12
area.height 16 => 16
area.height 20 => 20
area.height 5 => 5
area.height 10 => 10
area.height 15 => 15
area.height 20 => 20
area.height 25 => 25

但这只是伪装的一些嵌套for's

答案 2 :(得分:1)

由于没有开箱即用的方法,您可以尝试这里提出的解决方法:

从原始帖子中提取,所有信用均转到原始海报:Enumerating on Multi-dimentional arrays

public static class ArrayExtensions
{
    public static IEnumerable<T> ToEnumerable<T>(this Array target)
    {
    foreach (var item in target)
        yield return (T)item;
    }
}

答案 3 :(得分:1)

如果你想要一个更通用的LINQ类方法接受更高维数组。

public static class ArrayExtensions
{
    private static IEnumerable<int[]> CreatePermutations(int[] lengths, int pos = 0)
    {
        for (var i = 0; i < lengths[pos]; i++)
        {
            var newArray = (int[])lengths.Clone();
            newArray[pos] = i;
            if (pos + 1 >= lengths.Length)
            {
                yield return newArray;
                continue;
            }
            foreach (var next in CreatePermutations(newArray, pos + 1)) yield return next;
        }
    }
    public static Array Select<T,P>(this Array target, Func<T, P> func)
    {
        var dimensions = target.Rank;
        var lengths = Enumerable.Range(0, dimensions).Select(d => target.GetLength(d)).ToArray();
        var array = Array.CreateInstance(typeof(P), lengths);
        var permutations = CreatePermutations(lengths);
        foreach (var index in permutations)
        {
            array.SetValue(func((T)target.GetValue(index)), index);
        }
        return array;
    }
}

你可以称之为。

    var heightOnly = area.Select<Tile, int>(a => a.height);