読者です 読者をやめる 読者になる 読者になる

SelectMany があればいいんじゃないだろうか?

2次元配列を扱うのに、もう2重ループは必要ありませんね。

SelectManyと2次元配列の素敵な関係:Gushwell's C# Dev Notes

というのを読んで、むしろ LINQ っぽく扱えた方がうれしいんじゃないかな、と言うことで書いてみた。

static class Program
{
    static IEnumerable<S> SelectMany<T, S>(this T[,] self, Func<T, int, int, IEnumerable<S>> f)
    {
        for (int i = 0; i < self.GetLength(0); i++)
            for (int j = 0; j < self.GetLength(1); j++)
                foreach (var t in f(self[i, j], i, j))
                    yield return t;
    }

    static IEnumerable<S> SelectMany<T, S>(this T[,] self, Func<T, IEnumerable<S>> f)
    {
        return self.SelectMany((t, _, __) => f(t));
    }

    static void Main(string[] args)
    {
        int[,] nums = new int[,] {
            {13, 200,31, 43, 54 },
            {110,20, 330,410,50},
            {100,220,33, 40, 500}
        };
        foreach (var t in nums.SelectMany(t => new[] { t }))
            Console.WriteLine(t);
    }
}

これなら i とか j とかが欲しい場合でも、(t, i, j) => ... と受け取れるし。
Select も用意して、new[] { t } すらいらなくしてもいいかも。


追記。T4 ってみた。

<#@ template  debug="true" hostSpecific="true" #>
<#@ output extension=".cs" #>
<#@ Assembly Name="System.Core.dll" #>
<#@ Assembly Name="System.Windows.Forms.dll" #>
<#@ import namespace="System" #>
<#@ import namespace="System.IO" #>
<#@ import namespace="System.Diagnostics" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Collections" #>
<#@ import namespace="System.Collections.Generic" #>
<#
int n = 10;
#>
using System;
using System.Collections.Generic;

public static class Linq
{
<# for (int dim = 2; dim <= n; dim++) { #>
    public static IEnumerable<S> SelectMany<S, T>(this T[<#= new string(',', dim - 1) #>] self, Func<T, <#= Seq("int", ", ", 0, dim) #>, IEnumerable<S>> f)
    {
<# for (int i = 0; i < dim; i++) { #>
        for (int i<#= i #> = 0; i<#= i #> < self.GetLength(<#= i #>); i<#= i #>++)
<# } #>
            foreach (var t in f(self[<#= Seq("i{0}", ", ", 0, dim) #>], <#= Seq("i{0}", ", ", 0, dim) #>))
                yield return t;
    }

    public static IEnumerable<S> SelectMany<S, T>(this T[<#= new string(',', dim - 1) #>] self, Func<T, IEnumerable<S>> f)
    {
        return self.SelectMany((t, <#= Seq("_{0}", ", ", 0, dim) #>) => f(t));
    }

<# } #>
}
<#+
string Seq(string template, string sep, int begin, int end) {
    return string.Join(sep, Enumerable.Range(begin, end - begin).Select(i => string.Format(template, i)));
}
#>

おー、これはよいかも?