web-dev-qa-db-ja.com

汎用リストをCSV文字列に変換する

整数値のリスト(リスト)があり、コンマ区切り値の文字列を生成したいと思います。これは、リスト内のすべてのアイテムが単一のカンマ区切りリストに出力されることです。

私の考え... 1.リストをメソッドに渡します。 2. stringbuilderを使用してリストを繰り返し、コンマを追加します。3.最後の文字をテストし、コンマの場合は削除します。

あなたの考えは何ですか?これが最善の方法ですか?

将来的に整数(現在の計画)だけでなく、文字列、long、double、boolなどを処理したい場合、コードはどのように変わりますか?任意のタイプのリストを受け入れるようにします。

124
DenaliHardtail

フレームワークがすでに私たちのために行っていることは驚くべきことです。

List<int> myValues;
string csv = String.Join(",", myValues.Select(x => x.ToString()).ToArray());

一般的な場合:

IEnumerable<T> myList;
string csv = String.Join(",", myList.Select(x => x.ToString()).ToArray());

ご覧のとおり、実質的に違いはありません。 x.ToString()にカンマが含まれている場合は、実際に"\"" + x.ToString() + "\""を引用符(つまり、x.ToString())で囲む必要があることに注意してください。

これのわずかなバリエーションに関する興味深い読み物については、Eric Lippertのブログの Comma Quibbling を参照してください。

注:これは、.NET 4.0が正式にリリースされる前に書かれました。今、私たちは言うことができます

IEnumerable<T> sequence;
string csv = String.Join(",", sequence);

オーバーロードの使用 String.Join<T>(string, IEnumerable<T>) 。このメソッドは、各要素xx.ToString()に自動的に投影します。

226
jason

3.5では、私はまだこれを行うことができました。はるかに単純で、ラムダは必要ありません。

String.Join(",", myList.ToArray<string>());
12
Krishna

IEnumerableで呼び出すことができる拡張メソッドを作成できます。

public static string JoinStrings<T>(
    this IEnumerable<T> values, string separator)
{
    var stringValues = values.Select(item =>
        (item == null ? string.Empty : item.ToString()));
    return string.Join(separator, stringValues.ToArray());
}

次に、元のリストのメソッドを呼び出すだけです。

string commaSeparated = myList.JoinStrings(", ");
10
Whatsit

String.Joinを使用できます。

String.Join(
  ",",
  Array.ConvertAll(
     list.ToArray(),
     element => element.ToString()
  )
);
7
João Angelo

@Frank で指定されたリンクのコードとして、.NET汎用リストからCSVファイルを作成する すべての行を,で終了するという小さな問題がありましたそれを取り除くためにコードを修正しました。

/// <summary>
/// Creates the CSV from a generic list.
/// </summary>;
/// <typeparam name="T"></typeparam>;
/// <param name="list">The list.</param>;
/// <param name="csvNameWithExt">Name of CSV (w/ path) w/ file ext.</param>;
public static void CreateCSVFromGenericList<T>(List<T> list, string csvCompletePath)
{
    if (list == null || list.Count == 0) return;

    //get type from 0th member
    Type t = list[0].GetType();
    string newLine = Environment.NewLine;

    if (!Directory.Exists(Path.GetDirectoryName(csvCompletePath))) Directory.CreateDirectory(Path.GetDirectoryName(csvCompletePath));

    if (!File.Exists(csvCompletePath)) File.Create(csvCompletePath);

    using (var sw = new StreamWriter(csvCompletePath))
    {
        //make a new instance of the class name we figured out to get its props
        object o = Activator.CreateInstance(t);
        //gets all properties
        PropertyInfo[] props = o.GetType().GetProperties();

        //foreach of the properties in class above, write out properties
        //this is the header row
        sw.Write(string.Join(",", props.Select(d => d.Name).ToArray()) + newLine);

        //this acts as datarow
        foreach (T item in list)
        {
            //this acts as datacolumn
            var row = string.Join(",", props.Select(d => item.GetType()
                                                            .GetProperty(d.Name)
                                                            .GetValue(item, null)
                                                            .ToString())
                                                    .ToArray());
            sw.Write(row + newLine);

        }
    }
}
6
Ali Umair

ボディが文字列のリストの代わりにカスタムクラスオブジェクトのリストを変換する場合、クラスのcsv行表現でクラスのToStringメソッドをオーバーライドします。

Public Class MyClass{
   public int Id{get;set;}
   public String PropertyA{get;set;}
   public override string ToString()
   {
     return this.Id+ "," + this.PropertyA;
   }
}

その後、次のコードを使用して、このクラスリストをheader columnでCSVに変換できます

string csvHeaderRow = String.Join(",", typeof(MyClass).GetProperties(BindingFlags.Public | BindingFlags.Instance).Select(x => x.Name).ToArray<string>()) + Environment.NewLine;
string csv= csvHeaderRow + String.Join(Environment.NewLine, MyClass.Select(x => x.ToString()).ToArray());
6
Zain Ali

ニースのシンプルな拡張メソッドが好きです

 public static string ToCsv(this List<string> itemList)
         {
             return string.Join(",", itemList);
         }

次に、元のリストのメソッドを呼び出すだけです。

string CsvString = myList.ToCsv();

他のいくつかの提案よりもクリーンで読みやすい。

3
Griffo

これについて詳しく説明します post 。ここに簡単な説明とともにコードを貼り付けます。

ヘッダー行を作成するメソッドは次のとおりです。プロパティ名を列名として使用します。

private static void CreateHeader<T>(List<T> list, StreamWriter sw)
    {
        PropertyInfo[] properties = typeof(T).GetProperties();
        for (int i = 0; i < properties.Length - 1; i++)
        {
            sw.Write(properties[i].Name + ",");
        }
        var lastProp = properties[properties.Length - 1].Name;
        sw.Write(lastProp + sw.NewLine);
    }

このメソッドは、すべての値行を作成します

private static void CreateRows<T>(List<T> list, StreamWriter sw)
    {
        foreach (var item in list)
        {
            PropertyInfo[] properties = typeof(T).GetProperties();
            for (int i = 0; i < properties.Length - 1; i++)
            {
                var prop = properties[i];
                sw.Write(prop.GetValue(item) + ",");
            }
            var lastProp = properties[properties.Length - 1];
            sw.Write(lastProp.GetValue(item) + sw.NewLine);
        }
    }

そして、これらをまとめて実際のファイルを作成する方法を次に示します。

public static void CreateCSV<T>(List<T> list, string filePath)
    {
        using (StreamWriter sw = new StreamWriter(filePath))
        {
            CreateHeader(list, sw);
            CreateRows(list, sw);
        }
    }
3
SQLSuperHero

解決策は、(文字列の)リストをリストする場合にのみ機能します

Carにn個のプロパティがあるlist(of car)のような独自のオブジェクトの汎用リストがある場合、各carオブジェクトのPropertiesInfoをループする必要があります。

見てください: http://www.csharptocsharp.com/generate-csv-from-generic-list

3
Frank M.

CsvHelperライブラリはNugetで非常に人気があります。 https://github.com/JoshClose/CsvHelper/wiki/Basics

CsvHelperの使用は本当に簡単です。デフォルト設定は、最も一般的なシナリオ用にセットアップされています。

ここに少し設定データがあります。

Actors.csv:

Id,FirstName,LastName  
1,Arnold,Schwarzenegger  
2,Matt,Damon  
3,Christian,Bale

Actor.cs(アクターを表すカスタムクラスオブジェクト):

public class Actor
{
    public int Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

CsvReaderを使用したCSVファイルの読み取り:

var csv = new CsvReader( new StreamReader( "Actors.csv" ) );

var actorsList = csv.GetRecords();

CSVファイルへの書き込み

using (var csv = new CsvWriter( new StreamWriter( "Actors.csv" ) )) 
{
    csv.WriteRecords( actorsList );
}
2
Farb

汎用ToCsv()拡張メソッド:

  • Int16/32/64、float、double、decimal、およびToString()をサポートするものをサポート
  • オプションのカスタム結合セパレーター
  • オプションのカスタムセレクター
  • オプションのヌル/空の処理仕様(* Opt()オーバーロード)

使用例:

"123".ToCsv() // "1,2,3"
"123".ToCsv(", ") // "1, 2, 3"
new List<int> { 1, 2, 3 }.ToCsv() // "1,2,3"

new List<Tuple<int, string>> 
{ 
    Tuple.Create(1, "One"), 
    Tuple.Create(2, "Two") 
}
.ToCsv(t => t.Item2);  // "One,Two"

((string)null).ToCsv() // throws exception
((string)null).ToCsvOpt() // ""
((string)null).ToCsvOpt(ReturnNullCsv.WhenNull) // null

実装

/// <summary>
/// Specifies when ToCsv() should return null.  Refer to ToCsv() for IEnumerable[T]
/// </summary>
public enum ReturnNullCsv
{
    /// <summary>
    /// Return String.Empty when the input list is null or empty.
    /// </summary>
    Never,

    /// <summary>
    /// Return null only if input list is null.  Return String.Empty if list is empty.
    /// </summary>
    WhenNull,

    /// <summary>
    /// Return null when the input list is null or empty
    /// </summary>
    WhenNullOrEmpty,

    /// <summary>
    /// Throw if the argument is null
    /// </summary>
    ThrowIfNull
}   

/// <summary>
/// Converts IEnumerable list of values to a comma separated string values.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="values">The values.</param>        
/// <param name="joinSeparator"></param>
/// <returns>System.String.</returns>
public static string ToCsv<T>(
    this IEnumerable<T> values,            
    string joinSeparator = ",")
{
    return ToCsvOpt<T>(values, null /*selector*/, ReturnNullCsv.ThrowIfNull, joinSeparator);
}

/// <summary>
/// Converts IEnumerable list of values to a comma separated string values.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="values">The values.</param>
/// <param name="selector">An optional selector</param>
/// <param name="joinSeparator"></param>
/// <returns>System.String.</returns>
public static string ToCsv<T>(
    this IEnumerable<T> values,
    Func<T, string> selector,            
    string joinSeparator = ",") 
{
    return ToCsvOpt<T>(values, selector, ReturnNullCsv.ThrowIfNull, joinSeparator);
}

/// <summary>
/// Converts IEnumerable list of values to a comma separated string values.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="values">The values.</param>
/// <param name="returnNullCsv">Return mode (refer to enum ReturnNullCsv).</param>
/// <param name="joinSeparator"></param>
/// <returns>System.String.</returns>
public static string ToCsvOpt<T>(
    this IEnumerable<T> values,
    ReturnNullCsv returnNullCsv = ReturnNullCsv.Never,
    string joinSeparator = ",")
{
    return ToCsvOpt<T>(values, null /*selector*/, returnNullCsv, joinSeparator);
}

/// <summary>
/// Converts IEnumerable list of values to a comma separated string values.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="values">The values.</param>
/// <param name="selector">An optional selector</param>
/// <param name="returnNullCsv">Return mode (refer to enum ReturnNullCsv).</param>
/// <param name="joinSeparator"></param>
/// <returns>System.String.</returns>
public static string ToCsvOpt<T>(
    this IEnumerable<T> values, 
    Func<T, string> selector,
    ReturnNullCsv returnNullCsv = ReturnNullCsv.Never,
    string joinSeparator = ",")
{
    switch (returnNullCsv)
    {
        case ReturnNullCsv.Never:
            if (!values.AnyOpt())
                return string.Empty;
            break;

        case ReturnNullCsv.WhenNull:
            if (values == null)
                return null;
            break;

        case ReturnNullCsv.WhenNullOrEmpty:
            if (!values.AnyOpt())
                return null;
            break;

        case ReturnNullCsv.ThrowIfNull:
            if (values == null)
                throw new ArgumentOutOfRangeException("ToCsvOpt was passed a null value with ReturnNullCsv = ThrowIfNull.");
            break;

        default:
            throw new ArgumentOutOfRangeException("returnNullCsv", returnNullCsv, "Out of range.");
    }

    if (selector == null)
    {
        if (typeof(T) == typeof(Int16) || 
            typeof(T) == typeof(Int32) || 
            typeof(T) == typeof(Int64))
        {                   
            selector = (v) => Convert.ToInt64(v).ToStringInvariant();
        }
        else if (typeof(T) == typeof(decimal))
        {
            selector = (v) => Convert.ToDecimal(v).ToStringInvariant();
        }
        else if (typeof(T) == typeof(float) ||
                typeof(T) == typeof(double))
        {
            selector = (v) => Convert.ToDouble(v).ToString(CultureInfo.InvariantCulture);
        }
        else
        {
            selector = (v) => v.ToString();
        }            
    }

    return String.Join(joinSeparator, values.Select(v => selector(v)));
}

public static string ToStringInvariantOpt(this Decimal? d)
{
    return d.HasValue ? d.Value.ToStringInvariant() : null;
}

public static string ToStringInvariant(this Decimal d)
{
    return d.ToString(CultureInfo.InvariantCulture);
}

public static string ToStringInvariantOpt(this Int64? l)
{
    return l.HasValue ? l.Value.ToStringInvariant() : null;
}

public static string ToStringInvariant(this Int64 l)
{
    return l.ToString(CultureInfo.InvariantCulture);
}

public static string ToStringInvariantOpt(this Int32? i)
{
    return i.HasValue ? i.Value.ToStringInvariant() : null;
}

public static string ToStringInvariant(this Int32 i)
{
    return i.ToString(CultureInfo.InvariantCulture);
}

public static string ToStringInvariantOpt(this Int16? i)
{
    return i.HasValue ? i.Value.ToStringInvariant() : null;
}

public static string ToStringInvariant(this Int16 i)
{
    return i.ToString(CultureInfo.InvariantCulture);
}
0
crokusek

String.Joinの問題は、値に既に存在するコンマのケースを処理していないことです。コンマが存在する場合、値を引用符で囲み、既存のすべての引用符を二重引用符に置き換えます。

String.Join(",",{"this value has a , in it","This one doesn't", "This one , does"});

CSVモジュール を参照してください

0
vbjay

http://cc.davelozinski.com/c-sharp/the-fastest-way-to-read-and-process-text-files

このWebサイトは、バッファーライターを使用してファイルに書き込む方法についていくつかの広範なテストを行いました。文字列ビルダーを使用するのが最も遅い方法の1つである、行ごとの読み取りが最善の方法のようです。

私は彼のテクニックを使って、それをファイルに保存するものをうまく機能させています。

0
Chong Ching