読者です 読者をやめる 読者になる 読者になる

雑記 - otherwise

最近はDQ10しかやっていないダメ技術者がちまちまと綴る雑記帳

LINQ っていいですね

C# Perl

LINQ は SQL との構文の違いが引っかかって、どうにも手を出す気になれずにいたんですが、いつまでも食わず嫌いでいる訳にもいかないので、本腰を入れて見てみました。
……これ、無茶苦茶いいです。特に DB 房な私みたいな人間には最高かも。
サンプルコード。

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;

class Hoge {
  public string Name { get; set; }
  public string Ruby { get; set; }
  public int Japanese { get; set; }
  public int Math { get; set; }
}

class LinqTest {
  static void Main() {
    var data = new List<Hoge>() {
        new Hoge() { Name = "田中一郎", Ruby = "たなかいちろう",     Japanese =  90, Math =  65 },
        new Hoge() { Name = "佐藤浩二", Ruby = "さとうこうじ",       Japanese =  44, Math =  76 },
        new Hoge() { Name = "大川花子", Ruby = "おおかわはなこ",     Japanese =  95, Math =  88 },
        new Hoge() { Name = "渡辺忠",   Ruby = "わたなべただし",     Japanese =  26, Math =  32 },
        new Hoge() { Name = "小林良三", Ruby = "こばやしりょうぞう", Japanese =  66, Math = 100 }
      };
    
    var mathTop =
            from item in data
            where 70 <= item.Math
            orderby item.Math descending, item.Ruby
            select item;
    var averageTop =
            from item in data
            let summary = item.Japanese + item.Math
            let average = summary / 2
            where 70 <= average
            orderby summary descending, item.Ruby
            select new { Name = item.Name, Summary = summary, Average = average };
    
    Console.WriteLine("【数学 70 点以上】");
    foreach (var math in mathTop) {
      Console.WriteLine("{0}", math.Name);
      Console.WriteLine("  国語 : {0}", math.Japanese);
      Console.WriteLine("  数学 : {0}", math.Math);
    }
    Console.WriteLine();
    
    Console.WriteLine("【平均 70 点以上】");
    foreach (var average in averageTop) {
      Console.WriteLine("{0}", average.Name);
      Console.WriteLine("  合計 : {0}", average.Summary);
      Console.WriteLine("  平均 : {0}", average.Average);
    }
  }
}

出力結果。

【数学 70 点以上】
小林良三
  国語 : 66
  数学 : 100
大川花子
  国語 : 95
  数学 : 88
佐藤浩二
  国語 : 44
  数学 : 76

【平均 70 点以上】
大川花子
  合計 : 183
  平均 : 91
小林良三
  合計 : 166
  平均 : 83
田中一郎
  合計 : 155
  平均 : 77

さて、こんなに便利なものは perl でも是非使いたい。
って事で、誰か実装してください。<他力本願
……だって、同じ事やるのに perl だとこんな事しなきゃいけないんですよ。(いや、 C# だって内部では同じ様な事をやっているんだが)

my @math_excellent =
       sort {
         $b->{Math} <=> $a->{Math} or $a->{Name} cmp $b->{Name}
       }
         grep {
           60 < $_->{Math}
          }
            $data;

my @average_excellent =
       map {
         {
           Name => $_->{Name},
           Summary => $_->{Japanese} + $_->{Math},
           Average => ($_->{Japanese} + $_->{Math}) / 2
         }
       }
         sort {
           $b->{Japanese} + $b->{Math} <=> $a->{Japanese} + $a->{Math}
               or $a->{Name} cmp $b->{Name}
         }
           grep {
             60 < ($_->{Japanese} + $_->{Math}) / 2
           }
             @data;

でも、 LINQ を使えればこんな感じで書ける事になるはず。(ほとんど C# と一緒)

my $math_excellent = 
       $item from $data
       where 60 < $item->{Math}
       orderby $item->{Math} descending, $item->{Name}
       select $item;

my $average_excellent = 
       $item from $data
       let $summary = $item->{Japanese} + $item->{Math}
       let $average = $summary / 2
       where 60 < $average
       orderby $summary descending, $item->{Name}
       select { Name => $item->{Name}, Summary => $summary, Average => $average };

……さすがに厳しいかなぁ。(私の今の能力では要望するのが精一杯です)