2008年05月14日

もう一つの数学パズルをC#で解いてみる

  
Haskellでといた問題をC#で解いてみる。
普通に書けばこんな感じ。

for (int n = 1000; n < 9999; n++) {
int r = ReverseNumber(n);
if ( n != r && (n % r == 0) && (r > 1000) )
Console.WriteLine(n);
}
private static int ReverseNumber(int n) {
int ans = 0;
while (n > 0) {
int remainder = n % 10;
ans = ans * 10 + remainder;
n /= 10;
}
return ans;
}


C#3.0+LINQだと、

Enumerable.Range(1000, 8999)
.Where(n => {
int revnum = n.ReverseEnumerable().Aggregate(0, (a, x) => a * 10 + x);
return ((revnum != n) && (revnum >= 1000) && (n % revnum == 0));
})
.ToList().ForEach(s => Console.WriteLine(s));

static class IntExtenstions {
public static IEnumerable<int> ReverseEnumerable(this int n) {
while (n > 0) {
int remainder = n % 10;
n /= 10;
yield return remainder;
}
}
}

Haskellの影響を受け、普段使わないAggregateを無理やり使ってみた。
でも、全然短くならない orz...

C#3.0 + Achiral だと、

1000.UpTo(9999)
.Where(n => {
int revnum = n.ReverseEnumerable().Aggregate(0, (a, x) => a * 10 + x);
return ((revnum != n) && (revnum >= 1000) && (n % revnum == 0));
}).ConsoleWriteLine();

だ。ReverseEnumerable()は省略
うーん、普通のコードが一番簡潔だ。
やはり、なんでもかんでも、LINQを使おうってのは間違いかな。


この記事へのコメント
今回のケースでは、クエリー式を使った方が(letを使える分)簡潔になると思います。

var q =
  from n in Enumerable.Range(1000, 9000)
  let r = Int32.Parse(new String(n.ToString().Reverse().ToArray()))
  where r >= 1000 && r != n && n % r == 0
  select n;
Posted by nsharp at 2008年05月15日 09:41
nsharpさん
なるほど、let を使えばすっきり書けますね。
Haskellも面白いですが、LINQも楽しいですね。

でも、C#2.0までしか知らない人に、この問題を出し解いてもらった
後に、このコードを見せたらびっくりするでしょうね。

Posted by Gushwell at 2008年05月15日 20:55
 

この記事へのトラックバックURL

http://trackback.blogsys.jp/livedoor/gushwell/51510869
この記事へのトラックバック
ズバリ、タイトルのとおりである。 「窓際プログラマーの独り言 -C#の話題を中心に」から「もう一つの数学パズルをC#で解いてみる」のコメント。 http://blog.livedoor.jp/gushwell/archives/51510869.html#comments 大変恥ずかしながら、C# 3.0 LINQ のクエリ構文で ...
C# 3.0 LINQ のクエリ構文で let が使えるとは知らなかった【Developer @ ADJUST】at 2008年05月26日 23:45