C# コレクションを指定した文字で連結する

[前回] (http://qiita.com/pierusan2010/items/ff252b106a952da80084) に引き続き、ちょっと便利な拡張メソッドについて投稿します。

## コレクションを指定した文字で連結してくれるstring.Join()

System.Stringクラスの静的メソッド string.Join()は文字列に変換したコレクションの値を指定した文字で連結してくれます。

```csharp
public static string Join(string separator, params string[] values);
public static string Join(string separator, params object[] values);
public static string Join(string separator, IEnumerable<string> values);
public static string Join<T>(string separator, IEnumerable<T> values);
```
配列をログに出力する時などに便利です。
なんでも放り込めるobject の可変長引数を取るオーバーロードもあります。

```csharp
var intArray = new []{ 1, 2, 3, 4, 5, 6, 7, 8, 9 };
var str = string.Join( ", ", intArray );
var str2 = string.Join(" : ", DateTime.Now, "hoge", 123, 3.141592 );

Console.WriteLine( "intArray= [ " + str + " ]" );
Console.WriteLine("objects= [ " + str2 + " ]" );

// > intArray= [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ]
// > objects= [ 2013/12/21 21:42:41 ; hoge ; 123 ; 3.141592 ]

```

### フォーマットを指定してつなげる
各要素のフォーマットを指定したい場合もあります。
こんな感じになりますでしょうか。

```csharp
var sqrts = Enumerable.Range(1, 10).Select(n => Math.Sqrt(n));
//小数点以下3桁で表示
var str = string.Join(", ", sqrts.Select(x => x.ToString("0.000")));
Console.WriteLine(str);

// > 1.000, 1.414, 1.732, 2.000, 2.236, 2.449, 2.646, 2.828, 3.000, 3.162
```
こうなると、LINQ的にメソッドチェーンで繋げて書きたくなってきます。

```csharp
// この語順の方がしっくりきますが、LINQのJoinになってしまいます。
// sqrts.Select(x=>x.ToString("0.000")).Join()
// -> Aggregateで代用できます

var str = sqrts.Select(x=>x.ToString("0.000")).Aggregate((a, b)=>a + ", " + b );
Console.WriteLine(str);

// > 1.000, 1.414, 1.732, 2.000, 2.236, 2.449, 2.646, 2.828, 3.000, 3.162
```

### 拡張メソッドにしてスッキリさせる

メソッドチェーンにはなったけれども、`Aggregate((a,b)=>a+", "+ b)`  を余計に記述しなくてはなりません。拡張メソッドに切り出してもう少しスッキリさせてみましょう。

```csharp
public static class EnumerableExt
{
    public static string ConcatWith(this IEnumerable<double> source, string separator, string format)
    {
        return source.Select(x=>x.ToString(format)).Aggrigate((a,b) => a + separator + b);
    }
}
```

```csharp
var sqrts = Enumerable.Range( 1, 10 ).Select( n => Math.Sqrt( n ) );
var str = sqrts.ConcatWith( ", ", "0.000" );
```
### ジェネリックメソッドにする
ジェネリックにしてdouble以外にも対応させましょう。 
IFormattable を実装しているクラスであれば対応可能です。

```csharp
public interface IFormattable
{
    string ToString(string format, IFormatProvider formatProvider);
}
```

``` csharp
public static class EnumerableExt
{
    public static string ConcatWith<T>(this IEnumerable<T> source, string separator,
        string format, IFormatProvider provider = null) where T : IFormattable
    {
        return source.Select(x => x.ToString( format, provider ))
            .Aggrigate((a,b) => a + separator + b);
    }

    //ついでにフォーマットを指定しないバージョンも
    public static string ConcatWith<T>(this IEnumerable<T> source, string separator)
    {
        return string.Join(separator, source);
    }
}
```
使用例

```csharp
Console.WriteLine( new[]{ 1000, 1980, 3980, 4500, 6398 }.ConcatWith(", ", "C") );

var sqrts = Enumerable.Range( 1, 10 ).Select( n => Math.Sqrt( n ) );
Console.WriteLine( sqrts.ConcatWith(", ", "E03") );

var days = new[]{
        new DateTime(2013,1,1),
        new DateTime(2013,2,2),
        new DateTime(2013,3,3)
};
var culture = System.Globalization.CultureInfo.CreateSpecificCulture("en-US");
Console.WriteLine(days.ConcatWith("  ;  ", "D", culture));


// > ¥1,000, ¥1,980, ¥3,980, ¥4,500, ¥6,398
// > 1.000E+000, 1.414E+000, 1.732E+000, 2.000E+000, 2.236E+000, 2.449E+000, 2.646E+000, 2.828E+000, 3.000E+000, 3.162E+000
// > Tuesday, January 1, 2013 ; Saturday, February 2, 2013 ; Sunday, March 3, 2013
```