100 Little Programming Exercises – go-left Software - https://go-left.com/blog/programming/100-little-programming-exercises/
これのReverse The Inputです。引数は自動的に、スペースで区切られた単語ごとに配列に入れられるので、その配列を逆順にすればいいだけですが、最後の要素"END"は逆順にしません。
とりあえず書いたのは以下のコード。
static void Main(string[] args)
{
var list = args.ToList();
if (list.Last() != "END")
{
Console.WriteLine("args.Last() != \"END\"");
}
else
{
//http://melma.com/backnumber_120830_4798410/
//IEnumerable<T>.Reverse()は範囲の指定ができない。
//List<T>.Reverse()は範囲指定が出来るが、返り値がvoid。
list.RemoveAt(list.Count() - 1);
list.Reverse<string>().ToList().ForEach(arg => Console.WriteLine(arg));
}
}
例外処理はしておらず、LINQ拡張メソッドではなくList<T>の関数を呼んでるので、行数が多めだと思われます。
本来は多分配列の逆順を実装する練習なんでしょうけど、各要素を後ろから挿入するくらいしか思いつかなかった…
最初は最後の要素以外のReverse()(List<T>.Reverse(Int32, Int32))しようと思ったんですけど、RemoveしてIEnumerable<T>.Reverse()のほうがいい気がした。
IEnumerableだかにForEachが無いから、ListのForEachを使うためだけにToList()してる(どうやら副作用回避のため実装してないけれど、皆同様の拡張メソッド作ってしまうみたいだね)。
LINQ拡張メソッドのTake()を使う
結局、自分が困っているのは「どうやって最後の要素以外を逆順するか?」ということで、上の例だとRemoveAt()を用いてList<string>から要素を削除して、それからReverse()して対処してるわけです。んでも拡張メソッド一覧見てたら、「配列の一部だけを抜き出す」というTake()を見つけたので、じゃあそっちのほうが一行で済むよね?ということでこうしました。
static void Main(string[] args)
{
var endKey = "END";
if (args.Last() != endKey)
{
Console.WriteLine("args.Last() != " + endKey);
}
else
{
//http://melma.com/backnumber_120830_4798410/
//IEnumerable<T>.Reverse()は範囲の指定ができない。
//List<T>.Reverse()は範囲指定が出来るが、返り値がvoid。
args.ToList()
.Take(args.Length - 1)
.Reverse<string>()
.ToList().ForEach(arg => Console.WriteLine(arg));
}
}
このコードの問題は、args.ToList()した後に、argsのListを幾つ抜き出す(Take()する)かの指定に、Listする前のargsの要素数を参考にしているところ…本当だったらList<T>.Countを使うべきなんだろうけど、どうしたものか…これは病院から帰ってきて思いついたもの。