[前回] (http://qiita.com/pierusan2010/items/ff252b106a952da80084) に引き続き、ちょっと便利な拡張メソッドについて投稿します。
コレクションを指定した文字で連結してくれるstring.Join()
System.Stringクラスの静的メソッド string.Join()は文字列に変換したコレクションの値を指定した文字で連結してくれます。
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 の可変長引数を取るオーバーロードもあります。
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 ]
フォーマットを指定してつなげる
各要素のフォーマットを指定したい場合もあります。
こんな感じになりますでしょうか。
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的にメソッドチェーンで繋げて書きたくなってきます。
// この語順の方がしっくりきますが、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)
を余計に記述しなくてはなりません。拡張メソッドに切り出してもう少しスッキリさせてみましょう。
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);
}
}
var sqrts = Enumerable.Range( 1, 10 ).Select( n => Math.Sqrt( n ) );
var str = sqrts.ConcatWith( ", ", "0.000" );
ジェネリックメソッドにする
ジェネリックにしてdouble以外にも対応させましょう。
IFormattable を実装しているクラスであれば対応可能です。
public interface IFormattable
{
string ToString(string format, IFormatProvider formatProvider);
}
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);
}
}
使用例
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