クイズ

Brad Abrams氏のところから。
http://blogs.msdn.com/brada/archive/2004/10/29/249607.aspx
複数の配列の任意部分の合計を求める。

using System;
using System.Collections.Generic;

struct MyArraySegment<T>
{
    readonly T arr;
    readonly int offset;
    readonly int count;

    public MyArraySegment(T arr, int offset, int count)
    {
        this.arr = arr;
        this.offset = offset;
        this.count = count;
    }

    public T this[int index]
    {
        get { return arr[offset + index]; }
    }

    public int Count
    {
        get { return count; }
    }

    // 型変換 ArraySegment -> MyArraySegment
    public static implicit operator MyArraySegment<T>(ArraySegment<T> arr)
    {
        return new MyArraySegment<T>(arr.Array, arr.Offset, arr.Count);
    }
}

class Program
{
    static IEnumerable<T> Range<T>(T arr, int start, int count)
    {
        for (int i = start; i < start + count; ++i)
            yield return arr[i];
    }

    static IEnumerable<T> Concat<T>(params IEnumerable<T> args)
    {
        foreach (IEnumerable<T> e in args)
            foreach (T t in e)
                yield return t;
    }

    static int Sum(IEnumerable<int> e)
    {
        int ret = 0;
        foreach (int n in e)
            ret += n;
        return ret;
    }

    static int Sum(params ArraySegment<int> args)
    {
        int ret = 0;
        foreach (ArraySegment<int> arr in args)
            for (int i = arr.Offset; i < arr.Offset + arr.Count; ++i)
                ret += arr.Array[i];

        // ※ MyArraySegmentへ型変換しています
        // ↓これが出来たほうが便利なのに・・・
        ret = 0;
        foreach (MyArraySegment<int> arr in args)
            for (int i = 0; i < arr.Count; ++i)
                ret += arr[i];
        return ret;
    }

    static void Main(string args)
    {
        int set1 = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
        int set2 = { 2, 4, 6, 8, 10, 12, 14, 16, 18, 20 };
        int set3 = { 1, 3, 5, 7, 9, 11, 13, 15, 17, 19 };
        int set4 = { 1, 1, 2, 3, 5, 8, 13, 21 };
        int set5 = { 2, 3, 5, 7, 11, 13, 17, 19 };
        int set6 = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

        // 回答
        Console.WriteLine(Sum(
            new ArraySegment<int>(set1, 0, 1),
            new ArraySegment<int>(set2, 0, 1),
            new ArraySegment<int>(set3, 0, 1),
            new ArraySegment<int>(set4, 0, 1),
            new ArraySegment<int>(set5, 0, 1),
            new ArraySegment<int>(set6, 0, 1)));

        // こっちの方が好み(パフォーマンス悪いけど)
        Console.WriteLine(Sum(Concat(
            Range(set1, 0, 1), Range(set2, 0, 1), Range(set3, 0, 1),
            Range(set4, 0, 1), Range(set5, 0, 1), Range(set6, 0, 1))));

        Console.Read();
    }
}

ArraySegmentの使い方が趣旨ですが、微妙に使いにくい気も。IEnumeratableなどをサポートしていないのは構わないのですが、インデクサくらいは欲しかったかも。あと、本題とは関係ありませんが、explicit/implicitって初めて使いました。というか、存在を知りませんでした。(^^;