hakeの日記

Windows環境でプログラミングの勉強をしています。

C# - ラムダ式とデリゲート型

処理をひとつの固まりとして扱うのがラムダ式

        (引数リスト) => {処理}; 
        (引数リスト) => {処理; return 戻り値;};

引数がひとつの場合や、処理が単文の場合は括弧を省略できる。また処理が単文の場合はreturnも省略できる。



ラムダ式は、デリゲート型の変数や引数として扱うことができる。
デリゲート型には以下の様な種類がある。

Action型

値を返さない処理を扱う。

    Action<引数の型リスト> 変数 = (引数リスト) => {処理};
Func型

値を返す処理を扱う

    Func<引数の型リスト, 返り値の型> 変数 = (引数リスト) => {処理; return 戻り値;};
Predicate型

引数について処理を行った結果のbool値を返す

    Predicate<引数の型> 変数 = (引数) => { 処理; return bool値; };
Comparison型

2つの引数の大小の判定を行う。int値を返す。

  • 処理結果 < 0 : xがyより小さい
  • 処理結果 == 0 : xとyは等しい
  • 処理結果 > 0 : xがyより大きい
    Comparison<引数の型> 変数 = (x, y) => { 処理; return int値; };
Converter型

引数で与えられたオブジェクトに対し処理を行い、出力型として値を返す。
使用例は明日の日記に記載。

    Converter<引数の型,出力の型> 変数 = x =>  { 処理; return 出力の型の値; };

 

using System;
using System.Collections.Generic;

//ラムダ式

class MyMain
{
    public static void Main(string[] args)
    {
        //値を返さないデリゲートにラムダ式を代入
        //  Action<引数の型リスト> 変数 = (引数リスト) => {処理};
        Action<int, int> a = (x, y) => 
        {
            Console.WriteLine("{0} + {1} = {2}",x, y, x + y);
            Console.WriteLine("{0} * {1} = {2}",x, y, x * y);
        };
        a(2, 3);    //2 + 3 = 5
                    //2 * 3 = 6

        //  引数が1個の場合、処理が単文の場合は括弧を省略できる
        
        Action<int> b = x => Console.WriteLine("{0} * (-1) = {1}",x, x * -1);
        b(4);       //4 * (-1) = -4

        //値を返すデリゲートにラムダ式を代入
        //  Func<引数の型リスト, 返り値の型> 変数 = (引数リスト) => {処理; return 戻り値;};
        Func<int, int, string> c = (x, y) =>
        {
            var i = x + y;
            return i.ToString("D04");
        };
        Console.WriteLine(c(5, 6)); // 0011

        //  処理が単文の場合、returnは省略できる
        Func<int, string> d = x => x.ToString("D05");
        Console.WriteLine(d(5)); // 00005
        
        
        //ラムダ式を引数にして関数を呼ぶ
        Console.WriteLine(MyFunc( (x,y) => x + y, 4, 5) );//9
        Console.WriteLine(MyFunc( (x,y) => x - y, 4, 5) );//-1
        Console.WriteLine(MyFold( (x,y) => x + y, new int[]{1,2,3,4,5} ) );//15


        //引数が条件を満たすか否かのデリゲートにラムダ式を代入
        //  Predicate<引数の型> 変数 = (引数) => { 判別式 };
        Predicate<int> p = x => x % 2 == 0;
        Console.WriteLine(p(2));                    // True
        Console.WriteLine(p(3));                    // False
        var selected = MySelect(p, new List<int>(){1,2,3,4,5});
        foreach(var e in selected){ Console.Write("{0} ", e); }
        Console.WriteLine();                        // 2 4


        //2つの引数を比較するデリゲートにラムダ式を代入
        //  Comparison<引数の型> 変数 = (x, y) => { 判別式 };
        //  戻り値r
        //  r <  0 : xがyより小さい
        //  r == 0 : xとyは等しい
        //  r >  0 : xがyより大きい
        Comparison<int> cp = (x, y) => x - y;
        Console.WriteLine( MyCompare(cp, new int[]{1,2,5,4,3}) );         //5
        Console.WriteLine( MyCompare((x,y)=>y-x, new int[]{1,2,5,4,3}) ); //1

    }
    
    //ラムダ式を引数にする関数
    
    private static int MyFunc(Func<int, int, int> f, int x, int y)
    {
        return f(x, y);
    }

    private static int MyFold(Func<int, int, int> f, int[] ary)
    {
        //null許容型
        int? v = null;
        foreach(var e in ary)
        {
            if( v.HasValue ){ v = f((int)v, e); }
            else{ v = e; }
        }
        return (int)v;
    }

    private static List<int> MySelect(Predicate<int> p, List<int> ary)
    {
        var v = new List<int>();
        foreach(var e in ary)
        {
            if( p(e) ){ v.Add( e ); }
        }
        return v;
    }
    
    private static int MyCompare(Comparison<int> cp, int[] ary)
    {
        //null許容型
        int? v = null;
        foreach(var e in ary)
        {
            if( v.HasValue ){ v = cp((int)v, e) > 0 ? (int)v : e; }
            else{ v = e; }
        }
        return (int)v;
    }
}