2014年11月19日

C#で与えられた数字のケタ数を調べる

   このエントリーをはてなブックマークに追加 Clip to Evernote
どう書く?orgに感謝を込めて」シリーズ その50

このシリーズも、とうとう50回めです。まだストックがあるので、もうしばらくは続けるつもりです。

■問題  (出題者 : susuさん)
与えられた数字のケタ数と、最大桁の位を求めてください。
数字が2469なら4桁で最大桁は1000の位です。
600なら3と100、1なら1と1です。

最初に思い浮かんだ方法で書いたコードは、文字列に変換して桁数を求めるもの。
2つの値を求めなくちゃいけないので、戻り値は、Tuple を使いました。
でも、Item1 とかItem2という無味感想な名前は、僕の好みじゃないなー。

using System;

namespace Doukaku.Org {
    class Program {
        static void Main(string[] args) {
            Resolve(9);
            Resolve(99);
            Resolve(100);
            Resolve(-4532);
            Resolve(98765);
            Console.ReadLine();
        }

        static void Resolve(long n) {
            dynamic ans = DigitNumber(n);
            Console.WriteLine("{0} の桁数は {1}桁です。最大桁は {2}の位です", n, ans.Item1, ans.Item2);
        }

        static Tuple<int, long> DigitNumber(long n) {
            int fig = Math.Abs(n).ToString().Length;
            long place = (int)Math.Pow(10, fig - 1);
            return Tuple.Create(fig, place);
        }
    }
}

でも、数学の問題なのに、文字列使うのはやだなーと思い、 次に書いたのが、文字列にせずに、桁数を求めたもの。
1を10倍ずつしていって、もとの数の絶対値より大きくなるまで繰り返せば、 桁数が分かります。

static Tuple<int, long> DigitNumber(long n) {
    long absn = Math.Abs(n);
    int fig = 0;
    long place;
    for (place = 1; place <= absn; place *= 10)
        fig++;
    return Tuple.Create(fig, place);
}

だったら、log10でも見つかるよね、ということで書いたのが次のメソッド。

static Tuple<int, long> DigitNumber(long n) {
    int fig = (int)Math.Log10(Math.Abs(n)) + 1;
    long place = (long)Math.Pow(10, fig - 1);
    return Tuple.Create(fig, place);
}

  

Posted by gushwell at 21:34Comments(0)TrackBack(0)

2010年09月23日

2つの配列から「値のペア」を列挙する

   このエントリーをはてなブックマークに追加 Clip to Evernote
F#の記事を書いて思ったんですが、C#でも、2つの配列にある値から「値のペア」を列挙するような場面は結構あるなーと。

いろんな書き方が考えられるので、例として、Dictionayに値を追加するコードをいくつか試しに書いてみました。
すぐに思い浮かぶのが、for文を使った書き方。これが、一番簡単ですね。

でも、{ ] の中がもっと複雑で、インデックスによるアクセスが複数個所で必要になる場合は、
for 文は、面倒だなーって感じることがあります。
foreach 使いたいなーと思っても、
とか書くと、alpstrの各要素にアクセスできないし、
とか書ければいいんですが、できません。

それと、LINQ使いたいな、というときには、インデックスを使うやり方は使えません。

.NET Framework4だと、Enumerable.Zip があるので、こういった時に使えそうです。

でも、最後の引数のSelectorがめんどくさい。

Tuple が追加されたのだから、

という Tuple 決め打ちのメソッドが標準で用意されてもよかったのにと思います。
そうすれば、以下のようなコードが書けます。

Tuple 嫌いだという方は、C#4.0で導入された dynamic 使って、こんなメソッドを書きます。
IEnumerableジェネリックスの型指定を dynamic にして、匿名クラスのオブジェクトを返しています。
すると、以下のように、書けます。
実際、Tuple使わない理由もないので、このZip2はあまり意味ないですが、dynamic の可能性の一つとして 見てもらえればと思います。

最後に、再度断っておきますが、
ここで問題にしているのは、Dictionayオブジェクトに値を追加する方法ではなくて、
2つのコレクションから、値のペアを列挙する方法です。

10/24 追記

意外にも反応がたくさんあってびっくりしました。
何人かの方が、コメントやトラックバックで、別の解法を示してくれて 僕も勉強になりました。
いろいろな書き方があるってことは、C#が表現力豊かな言語である証ですね。

なお、この記事を最初にアップしたときには、

>それと、LINQ使いたいな、というときには、このやり方は使えません。

と書きました。その後、

>それと、LINQ使いたいな、というときには、インデックスを使うやり方は使えません。

と書き直しましたが、
これは、for 文だと、続けて LINQの拡張メソッドに続けられないけど、Zipなどを使えば、
そのあとに、Where や Select や Count などが続けられる、という意図でした。
LINQでは、「2つの配列から値のペアを列挙することができない」という意図で、
書いたのではなかったのですが、僕の表現のあいまいさのおかげ(?)で
いろんなコードを見ることができました。
  
Posted by gushwell at 17:12Comments(3)TrackBack(2)