linq Map多维数组

mcdcgff0  于 2022-12-06  发布在  其他
关注(0)|答案(4)|浏览(132)

我有下面的课

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

我有一个二维的Tiles数组

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

如何将我的区域从Tile[,]Map到int[,],其中仅保存高度?
我试着这样做:

area.Select(tile => tile.height)

但C#多维数组显然没有实现IEnumerable。
我该如何解决这个问题?

hl0ma9xz

hl0ma9xz1#

我该如何解决这个问题?
通过 * 编写代码 *。没有“选择”功能,因此请自行创建:

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运算符但可以作为扩展方法实现的运算符?
k7fdbhmy

k7fdbhmy2#

由于没有现成的方法来完成此操作,您可以尝试此处建议的解决方法:
摘自原帖,所有功劳归原帖: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;
    }
}
8e2ybdfx

8e2ybdfx3#

如果你真的,真的,真的想,你可以这样做:

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

您的链接:

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

23c0lvtd

23c0lvtd4#

And if you want a more generic LINQ-like method accepting higher dimensional arrays.

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

Which you can call like.

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

相关问题