徳島ゲーム開発ごっこ 技術ブログ

ゲームを作るために役に立ったり立たなかったりする技術を学んでいきます!

【C#,LINQ】DefaultIfEmpty~配列やリストが空のときはデフォルトの値を取得したいとき~

 C#のLINQの関数であるDefaultIfEmpty()の使い方についてです。
 配列やリストが空のときにデフォルトのなる要素を取得するようにすることが出来ます。
f:id:urahimono:20180702001217p:plain


この記事には.NET Framework 4.6.1を使用しています。

空のときはデフォルト!

 配列やリストの中身が空のときありますよね。
 そんなときでも、とりあえず何かしらの要素が欲しいときありませんか。

 こんなときはLINQDefaultIfEmpty()が使えます。

public static IEnumerable<TSource> DefaultIfEmpty<TSource>( this IEnumerable<TSource> source );
Enumerable.DefaultIfEmpty(TSource) メソッド (IEnumerable(TSource)) (System.Linq)

 DefaultIfEmpty()を使うと、使った配列やリストが空だった場合、その要素の型のデフォルト値が返されます。

Program.cs

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

public static class Program
{
    static void Main( string[] args )
    {
        int[] numbersA  = new int[] { 0, 1, 2 };
        int[] numbersB  = new int[] {};

        IEnumerable<int> numbersAPlus   = numbersA.DefaultIfEmpty();
        IEnumerable<int> numbersBPlus   = numbersB.DefaultIfEmpty();

        // 結果発表
        System.Console.WriteLine( "numbersA     :{0}", numbersA.Text() );
        System.Console.WriteLine( "numbersAPlus :{0}", numbersAPlus.Text() );
        System.Console.WriteLine( "numbersB     :{0}", numbersB.Text() );
        System.Console.WriteLine( "numbersBPlus :{0}", numbersBPlus.Text() );

        // 入力待ち用
        System.Console.ReadKey();
    }

    /// <summary>
    /// 簡易的なシーケンスのテキスト取得処理
    /// </summary>
    public static string Text( this IEnumerable i_source )
    {
        string text = string.Empty;
        foreach( var value in i_source )
        {
            text += string.Format( "[{0}], ", value );
        }
        return text;
    }

} // class Program

numbersA :[0], [1], [2],
numbersAPlus :[0], [1], [2],
numbersB :
numbersBPlus :[0],

デフォルトの要素を指定する!

 型のデフォルト値よりも、自分で指定したデフォルトの値が良い場合は、DefaultIfEmpty()の引数に、空だった場合に返してほしい値を渡してあげればOKです。

public static IEnumerable<TSource> DefaultIfEmpty<TSource>( this IEnumerable<TSource> source, TSource defaultValue );
Enumerable.DefaultIfEmpty(TSource) メソッド (IEnumerable(TSource), TSource) (System.Linq)

Program.cs

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

public static class Program
{
    static void Main( string[] args )
    {
        int[] numbersA      = new int[] { 0, 1, 2 };
        int[] numbersB      = new int[] {};
        int   defaultNumber = -1;

        IEnumerable<int> numbersAPlus   = numbersA.DefaultIfEmpty( defaultNumber );
        IEnumerable<int> numbersBPlus   = numbersB.DefaultIfEmpty( defaultNumber );

        // 結果発表
        System.Console.WriteLine( "numbersA     :{0}", numbersA.Text() );
        System.Console.WriteLine( "numbersAPlus :{0}", numbersAPlus.Text() );
        System.Console.WriteLine( "numbersB     :{0}", numbersB.Text() );
        System.Console.WriteLine( "numbersBPlus :{0}", numbersBPlus.Text() );

        // 入力待ち用
        System.Console.ReadKey();
    }

    /// <summary>
    /// 簡易的なシーケンスのテキスト取得処理
    /// </summary>
    public static string Text( this IEnumerable i_source )
    {
        string text = string.Empty;
        foreach( var value in i_source )
        {
            text += string.Format( "[{0}], ", value );
        }
        return text;
    }

} // class Program

numbersA :[0], [1], [2],
numbersAPlus :[0], [1], [2],
numbersB :
numbersBPlus :[-1],

 自作のクラスでも以下のように使うことが出来ます。

Program.cs

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

public static class Program
{
    private class Parameter
    {
        public int      ID      { get; set; }
        public int      Age     { get; set; }
        public string   Name    { get; set; }
        
        public override string ToString()
        {
            return string.Format( "ID:{0}, Age:{1}, Name:{2}", ID, Age, Name );
        }
    }

    static void Main( string[] args )
    {
        Parameter[] parametersA = new Parameter[]
        {
            new Parameter() { ID = 0, Age = 52, Name = "正一郎" },
            new Parameter() { ID = 8, Age = 28, Name = "清次郎" },
            new Parameter() { ID = 3, Age = 20, Name = "誠三郎" },
            new Parameter() { ID = 4, Age = 18, Name = "征史郎" },
        };

        Parameter[] parametersB         = new Parameter[] {};
        Parameter   defaultparameter    = new Parameter() { ID = -1, Age = 0, Name = "名無し" };


        IEnumerable<Parameter> parametersAPlus  = parametersA.DefaultIfEmpty( defaultparameter );
        IEnumerable<Parameter> parametersBPlus  = parametersB.DefaultIfEmpty( defaultparameter );

        // 結果発表
        System.Console.WriteLine( "parametersA     :{0}", parametersA.Text() );
        System.Console.WriteLine( "parametersAPlus :{0}", parametersAPlus.Text() );
        System.Console.WriteLine( "parametersB     :{0}", parametersB.Text() );
        System.Console.WriteLine( "parametersBPlus :{0}", parametersBPlus.Text() );

        // 入力待ち用
        System.Console.ReadKey();
    }

    /// <summary>
    /// 簡易的なシーケンスのテキスト取得処理
    /// </summary>
    public static string Text( this IEnumerable i_source )
    {
        string text = string.Empty;
        foreach( var value in i_source )
        {
            text += string.Format( "[{0}], ", value );
        }
        return text;
    }

} // class Program

parametersA :[ID:0, Age:52, Name:正一郎], [ID:8, Age:28, Name:清次郎], [ID:3
, Age:20, Name:誠三郎], [ID:4, Age:18, Name:征史郎],
parametersAPlus :[ID:0, Age:52, Name:正一郎], [ID:8, Age:28, Name:清次郎], [ID:3
, Age:20, Name:誠三郎], [ID:4, Age:18, Name:征史郎],
parametersB :
parametersBPlus :[ID:-1, Age:0, Name:名無し],

 こんな感じでDefaultIfEmpty()を七兆回ほど使ってみてください。

LINQのリンク