2015年6月30日火曜日

『月光~the lunatic~』

イブニングで5週掲載された、ウチヤマユージさんの『月光~the lunatic~』の単行本が発売されたようなので、おススメを。



表題作と他一遍の中編集。イブニング掲載時に読みましたが、すごく良かった。絵も話もとても好み。

静かに始まる第一話。一見他愛ない日常に見えて、ちらほらと異常がちりばめられる。
話が進むと時間軸を行ったり来たりしながら展開していき、少しずつ全容が見えてくる。
すべてが明らかになった後、結末は「んなあほな」と思いつつ、なんだか妙に晴れやかな気分。

この作者さんは知りませんでしたが、今後に期待大です。

2015年6月25日木曜日

『僕だけがいない街』アニメ化決定

『僕だけがいない街』の最新刊の発売はいつかな?と、調べていたらこんなのを見つけました。

『僕だけがいない街』アニメ化決定&最新刊発売!各界の著名人も絶賛

え?アニメ化?まじで?だって、未完結の状態でこれアニメになんかできないでしょ?と思いつつ、記事を読むと、『2016年1月フジテレビ「ノイタミナ」枠でアニメスタート』とあった。

これは全部妄想だけど、アニメが2クールだとすると、2016年6月にアニメが最終回になるわけで。そうすると、2015年7月に単行本6巻が発売で、1冊出るのに半年かかるので、2016年1月に7巻、2016年7月に8巻が、最終巻として出るなら帳尻は合う。一回くらい休載しても何とか間に合うか。

『四月は君の嘘』もそんな感じじゃなかったっけ?あれもノイタミナ。

そーすると、あと12話で完結??


…なんてことを考えながら、はやく6巻読みたいな。単行本で追いかけてるので、続きが気になって。

2015年6月22日月曜日

ToDictionaryで重複のない辞書を作る

シンプルなTipsをひとつ。

LINQのToDictionaryメソッドは、コレクションから辞書を簡単に作ってくれる、使用頻度の高い便利なメソッドです。ただ、指定したキーセレクタの結果、キーが重複していると例外(ArgumentException)をスローします。例えば、以下のようなコード。

var collection = new [] { "One", "Two", "Three", "Four" };
var dic = collection.ToDictionary(c => c.First());

この例では、文字列の最初の文字をキーにするので、キー'T'が重複します。しかし、キーに対して最初に現れた値を登録するような、単純なルールで重複を排除して辞書を作りたいケースがあります。

さて、どう解決しましょうか。ToDictionaryのメソッドで、重複を排除するようなオーバーロードがあれば簡単ですが、ないですね。なので、こんなコードではどうでしょうか?

var collection = new [] { "One", "Two", "Three", "Four" };
var dic = collection.GroupBy(c => c.First())
    .ToDictionary(g => g.Key, g => g.First());

ToDictionaryの前に、一旦最初の文字でグループ化しておいて、そのグループキーと最初の値を辞書のエントリとしてみました。

2015年4月16日木曜日

来週のサンデー

銀の匙が載りますか!戻ってきてくれてよかった。
BIRDMENも掲載される号だし。楽しみだー。

2015年1月14日水曜日

Import時の重複チェックにLINQ(GroupBy)を利用する

外部のシステムからデータをインポートする機能は、多くのシステムで必要になってきます。CSVなりXMLなりの標準化された形式で送られたデータを、一括でシステムに取り込む機能です。

この場合、普通の入力とは異なり、一括で処理するゆえのメンドクササがありますよね。

たとえば、ユーザ情報を外部システムからインポートする場合。想定するケースによりますが、ユーザIDがインポートデータ中に重複して存在する可能性があったりすると、せめて取り込みの事前のチェックを行っておきたいケースもあると思います。が、これが結構面倒。

これをGroupByメソッドを活用して、なるべくシンプルに記述してみます。想定する前提はこんな感じだとします。
  • インポートするユーザ情報データは、すでにオブジェクトへのマッピングがされており、コレクション化されている前提。
  • ユーザ情報データは「UserInfo」クラスに格納されており、ユーザIDは文字列のメンバUserIdとして存在する。
  • ユーザ情報データのコレクションを入力として、ユーザIDの重複チェックを行う静的メソッド「ValidateNotDuplicated」を作成する。
  • このメソッドは、ユーザIDの重複があった場合、コンソールにエラーメッセージを出力し、メソッドの戻り値はfalseを返す。重複がなければそのままtrueを返す。
  • エラーメッセージには、重複しているユーザIDを表示する。複数のユーザIDが重複していた場合は、そのすべてを表示する。
このような処理を書くと、こんな感じになりますね。

public static bool ValidateNotDuplicated(IEnumerable<UserInfo> users)
{
  var dupusers = users.GroupBy(u => u.UserId)
    .Where(g => g.Count() > 1)
    .Select(g => g.Key)
    .ToArray();

  if (dupusers.Length > 0)
  {
    Console.WriteLine("User:{0} was duplicated.", string.Join(",", dupusers);
    return false;
  }

  return true;
}

つまり、「コレクションをUserIdでグループ化し(GroupBy)」、「そのうち2つ以上存在するものを選び出し(Where)」、「キーとなっているUserIdのみを対象として(Select)」、「配列に変換する(ToArray)」。という処理を行っています。

ちょっとだけバリエーションを考えて見ましょうか。たとえば、
  • 「UserInfo」クラスには、データが更新された時間を示す「Updated」メンバ(DateTime型)も持っている。
  • このユーザ情報データのコレクションを入力として、ユーザIDが重複していた場合、「Updated」が最新のもの以外を取り除いたコレクションを返す、静的メソッド「SelectLatest」を作成する。
この場合ならもっとシンプルで、

public static IEnumerable<UserInfo> SelectLatest(IEnumerable<UserInfo> users)
{
  return users.GroupBy(u => u.UserId)
    .Select(g => g.OrderByDescending(u => u.Updated).First());
}
これだけになりますね。


2015年1月12日月曜日

Enumerable.GroupByメソッドの威力

2015年も明けて間もなく2週間が経とうとしています。

おそくなりましたが、今年もよろしくお願いします。

今年の目標は「去年のエントリ数を超える」こと。2014年は5本だったようなので、達成できそうな目標にしてみました。

一発目のエントリは、「GroupBy」をテーマにしてみます。非常に強力なLINQのメソッドですが、なかなか使う機会が少ない人も多いのではないかと思います。

「GroupBy」メソッドは、SQLを触ったことのある人なら「group by」句をイメージしてもらうとほぼ間違いなしで、つまりは「コレクション内の各要素を、ある条件でグループ分けする」メソッドです。ぱっと見面倒そうですが、使い方はいたってシンプルです。

サンプルを書いてみましょう。

  • データメンバとして、日付(Date)と売上額(Amount)を持つSalesクラスがあります。
  • Salesクラスは、ある指定期間の日別の売上額を列挙するEnumerate静的メソッドを持ちます。
  • ここで、上記Salesクラスを使い、ある年(ここでは2014年)の曜日別の売り上げの総合計、平均値、中間値を算出します。
この処理は以下のコードになります。

static void ShowGroupedAmounts()
{
  var from = new DateTime(2014, 1, 1);
  var to = new DateTime(2014, 12, 31);
  var group = Sales.Enumerate(from, to)
    .GroupBy(s => s.Date.DayOfWeek)
    .OrderBy(g => g.Key);

  Console.WriteLine("DayOfWeak,Total Amount,Average,Median");

  foreach (var g in group)
  {
    var cnt = g.Count();

    Console.WriteLine(
      "{0},{1},{2},{3}",
      g.Key,
      g.Sum(s => s.Amount),
      Math.Round(g.Average(s => s.Amount), 1),
      g.OrderBy(s => s.Amount).Skip(cnt / 2).First().Amount);
  }
}

非常にシンプルなコードで、キー(ここでは曜日)ごとにグループ化できていると思います。なお、GroupByメソッドの戻り値は以下の形態になります。

IEnumerable<IGrouping<DayOfWeak, Sales>>

IGroupingは、IEnumerable<T>にキー情報を加えたもの。と考えればOKです。

2014年12月21日日曜日

大河ドラマ『軍師官兵衛』最終回

今年の大河は面白かった。合戦のシーンがもう少し欲しかったかな。とか、鳥取城攻めがまるっとなかったりはちょっと残念でしたが。

来年はどうかな。再来年は今から楽しみ。