配列を逆順でアクセスしたい §
サンプルソースに6パターン書いてみました。
方法1は普通にforループをまわして添え字にアクセスする際に最大値から引いて逆順の添え字を作り出します。
方法2はforループを逆順でまわしてしまいます。
方法3はLINQのRverseメソッドで逆順にします。ソースは最も簡潔ですが実行効率はforに負けます。
方法4はSkipする数を減らしていき結果として逆順でアクセスします。これもLINQです。
方法5はLINQで最後の要素を取得して、1つ1つ列挙の長さを切り詰めていきます。
方法6は再帰という手法を使った例です。forもforeachも使いませんが、データが大きいとスタックを大量に消費します。効率も良くありません。
お勧めは方法1か2か3です。
4と5と6は【そういう方法もある】という程度で理解しておき、特に覚える必要はありません。
罠の数々 §
- やり方は多いがどれが正解という話ではない。状況、用途によって使い分けられるようにバリエーションの特徴を理解しておこう
- 関数型の言語を使う場合は方法6の再帰が必要になる場合があるが、C#は関数型ではないので必須ではない。ただし、C#でも再帰を使った方が良いケースはあるので、再帰は理解しておこう
参考リンク §
for (C# リファレンス)
Enumerable.Reverse<TSource>(IEnumerable<TSource>) メソッド
Enumerable.Skip<TSource>(IEnumerable<TSource>, Int32) メソッド
Enumerable.First メソッド
Enumerable.Take<TSource>(IEnumerable<TSource>, Int32) メソッド
Enumerable.Count メソッド
単純に逆順にするだけならReverseメソッドが最強である。しかし、単純に逆順ではなく加工が必要なら、他のメソッドを組み合わせで実現することになる。SkipメソッドやTakeメソッドの出番だ。上記リンクから、メソッドの機能とバリエーションを確認しておこう。
それから、効率重視だとLINQは弱い。forループを回した方が速いこともある。forループを自由自在に使えるように上記リンクから飛んで機能を確認しておこう。
リポジトリ §
https://github.com/autumn009/cshowto
Reverse §
using System;
using System.Collections.Generic;
using System.Linq;
class Program
{
private static void recursion(IEnumerable<int> e)
{
if (e.Count() > 0)
{
recursion(e.Skip(1));
Console.Write(e.First());
}
}
static void Main()
{
int[] ar = { 1, 2, 3 };
// 方法1 ストレートfor
for (int i = 0; i < ar.Length; i++)
{
Console.Write(ar[ar.Length-i-1]);
}
Console.WriteLine();
// 方法2 リバースfor
for (int i = ar.Length - 1; i >= 0; i--)
{
Console.Write(ar[i]);
}
Console.WriteLine();
// 方法3 LINQ
foreach (var item in ar.Reverse())
{
Console.Write(item);
}
Console.WriteLine();
// 方法4 LINQ2
for (int i = 0; i < ar.Length; i++)
{
Console.Write(ar.Skip(ar.Length-i-1).First());
}
Console.WriteLine();
// 方法5 LINQ3
IEnumerable<int> a = ar.ToArray();
for (; ; )
{
if (a.Count() == 0) break;
Console.Write(a.Last());
a = a.Take(a.Count()-1);
}
Console.WriteLine();
// 方法6 再帰
recursion(ar);
Console.WriteLine();
}
}
実行結果
321
321
321
321
321
321