web-dev-qa-db-ja.com

LINQを使用して文字列を連結する

古い学校を書くための最も効率的な方法は何ですか:

StringBuilder sb = new StringBuilder();
if (strings.Count > 0)
{
    foreach (string s in strings)
    {
        sb.Append(s + ", ");
    }
    sb.Remove(sb.Length - 2, 2);
}
return sb.ToString();

... LINQで?

316
tags2k

この答えは質問で要求された通りのLINQ(Aggregate)の使い方を示しており、日常の使用を意図したものではありません。これはStringBuilderを使用していないので、非常に長いシーケンスではひどいパフォーマンスになります。通常のコードでは、他の例のようにString.Joinを使用してください 答え

このように集約クエリを使用してください。

string[] words = { "one", "two", "three" };
var res = words.Aggregate(
   "", // start with empty string to handle empty list case.
   (current, next) => current + ", " + next);
Console.WriteLine(res);

これは出力します:

一二三

集約は、値のコレクションを受け取り、スカラー値を返す関数です。 T-SQLの例としては、min、max、sumなどがあります。 VBとC#はどちらも集約をサポートしています。 VBとC#はどちらも拡張メソッドとして集約をサポートしています。ドット表記法を使用して、 IEnumerable オブジェクトのメソッドを呼び出すだけです。

集計クエリはすぐに実行されることを忘れないでください。

より詳しい情報 - MSDN:Aggregate Queries


本当にAggregateを使いたい場合は、 CodeMonkeyKing のコメントで提案されているStringBuilderを使ってvariantを使用してください。これは、通常のString.Joinとほぼ同じコードになります。

 var res = words.Aggregate(
     new StringBuilder(), 
     (current, next) => current.Append(current.Length == 0? "" : ", ").Append(next))
     .ToString();
503
Jorge Ferreira
return string.Join(", ", strings.ToArray());

.NET 4では、string.Joinを受け入れるIEnumerable<string>用の新しい オーバーロード があります。その結果、コードは次のようになります。

return string.Join(", ", strings);
319
Amy B

なぜLinqを使うのですか?

string[] s = {"foo", "bar", "baz"};
Console.WriteLine(String.Join(", ", s));

私の覚えている限り、それは完璧に動作し、どんなIEnumerable<string>も受け入れます。ここではAggregatename__は必要ありません。

121
Armin Ronacher

Aggregate拡張メソッドを見ましたか?

var sa = (new[] { "yabba", "dabba", "doo" }).Aggregate((a,b) => a + "," + b);
75
Robert S.

私のコードからの本当の例:

return selected.Select(query => query.Name).Aggregate((a, b) => a + ", " + b);

クエリは、文字列であるNameプロパティを持つオブジェクトです。選択したリストにあるすべてのクエリの名前をカンマで区切って指定します。

56

これは私が他の答えと対処した問題を見た後に解決したJoin/Linqの組み合わせアプローチです 同じ質問で (つまり、AggregateとConcatenateは0要素で失敗する)。

string Result = String.Join(",", split.Select(s => s.Name));

または(sが文字列ではない場合)

string Result = String.Join(",", split.Select(s => s.ToString()));

  • 単純な
  • 読みやすく理解しやすい
  • 一般的な要素に対して動作します
  • オブジェクトまたはオブジェクトプロパティの使用を許可
  • 長さ0の要素のケースを処理します
  • 追加のLinqフィルタリングと共に使用できます
  • (少なくとも私の経験では)うまく機能する
  • 実装するために追加のオブジェクト(例えばStringBuilder)を(手動で)作成する必要はありません。

そしてもちろん、Joinは他のアプローチ(forforeach)に潜入する厄介な最後のカンマを扱います。それが私がそもそもLinqの解決策を探していた理由です。

28
brichins

StringBuilderではAggregateを使用できます。

  List<string> strings = new List<string>() { "one", "two", "three" };

  StringBuilder sb = strings
    .Select(s => s)
    .Aggregate(new StringBuilder(), (ag, n) => ag.Append(n).Append(", "));

  if (sb.Length > 0) { sb.Remove(sb.Length - 2, 2); }

  Console.WriteLine(sb.ToString());

Selectは、あなたがもっとLINQのことができることを示すためだけにあります。)

28
jonathan.s

stringBuilderとSelect&Aggregateの場合の3000要素以上のパフォーマンスデータ

単体テスト - 期間(秒)
LINQ_StringBuilder - 0.0036644
LINQ_Select.Aggregate - 1.8012535

    [TestMethod()]
    public void LINQ_StringBuilder()
    {
        IList<int> ints = new List<int>();
        for (int i = 0; i < 3000;i++ )
        {
            ints.Add(i);
        }
        StringBuilder idString = new StringBuilder();
        foreach (int id in ints)
        {
            idString.Append(id + ", ");
        }
    }
    [TestMethod()]
    public void LINQ_SELECT()
    {
        IList<int> ints = new List<int>();
        for (int i = 0; i < 3000; i++)
        {
            ints.Add(i);
        }
        string ids = ints.Select(query => query.ToString())
                         .Aggregate((a, b) => a + ", " + b);
    }
22
user337754

私はいつも拡張メソッドを使います。

public static string JoinAsString<T>(this IEnumerable<T> input, string seperator)
{
    var ar = input.Select(i => i.ToString()).ToArray();
    return string.Join(seperator, ar);
}
15
Kieran Benton

'超クールなLINQのやり方'で、LINQが拡張メソッドを使って関数型プログラミングをより美しくする方法について話しているかもしれません。つまり、関数を入れ子にするのではなく、視覚的に線形の方法で(順番に)連鎖させることができる構文糖です。例えば:

int totalEven = Enumerable.Sum(Enumerable.Where(myInts, i => i % 2 == 0));

このように書くことができます:

int totalEven = myInts.Where(i => i % 2 == 0).Sum();

2番目の例が読みやすいことがわかります。また、インデントの問題や式の末尾に表示されるLispy閉じ括弧の数を少なくして、関数を追加する方法もわかります。

他の多くの答えでは、String.Joinが最も速いまたは最も簡単な読み方であるため、この方法が適していると述べています。しかし、私の解釈である '超クールなLINQ方法'を使用する場合、答えはString.Joinを使用することです。方法。 sa.Concatenate(", ")を書きたいのであれば、このようなものを作成する必要があります。

public static class EnumerableStringExtensions
{
   public static string Concatenate(this IEnumerable<string> strings, string separator)
   {
      return String.Join(separator, strings);
   }
}

これにより、直接呼び出しと同等のパフォーマンスが得られるコード(少なくともアルゴリズムの複雑さの点で)が提供され、特にブロック内の他のコードが連鎖関数スタイルを使用している場合はコードが読みやすくなります。 。

12
tpower

ここでは純粋なLINQを単一の式として使用しています。

static string StringJoin(string sep, IEnumerable<string> strings) {
  return strings
    .Skip(1)
    .Aggregate(
       new StringBuilder().Append(strings.FirstOrDefault() ?? ""), 
       (sb, x) => sb.Append(sep).Append(x));
}

そして、そのかなり速いです!

5
cdiggins

これにはさまざまな代替の答えがあります 前の質問 - これは確かにソースとして整数配列をターゲットにしていましたが、一般化された答えを受け取りました。

5
Jon Skeet

私はちょっとカンニングをして、これに新しい答えを捨てるつもりです。それはコメントの中にそれを固執するのではなく、ここですべての最高のものをまとめるようです。

だから、これを一行にすることができます:

List<string> strings = new List<string>() { "one", "two", "three" };

string concat = strings        
    .Aggregate(new StringBuilder("\a"), 
                    (current, next) => current.Append(", ").Append(next))
    .ToString()
    .Replace("\a, ",string.Empty); 

編集:最初に空の列挙型をチェックするか、式の最後に.Replace("\a",string.Empty);を追加します。ちょっと賢くなりすぎようとしていたのかもしれません。

@ a.friendからの回答は多少パフォーマンスが良いかもしれませんが、Removeと比べてReplaceがフードの下で何をするのかわかりません。何らかの理由で\ a'sで終わる文字列を連結したい場合は、他の唯一の警告として、区切り文字が失われる可能性があります。その場合は 他の空想の文字 から選ぶ必要があります。

3
Chris Marisic

LINQとstring.join()を非常に効果的に組み合わせることができます。ここで私は文字列から項目を削除しています。これを行うより良い方法もありますが、ここにそれはあります:

filterset = String.Join(",",
                        filterset.Split(',')
                                 .Where(f => mycomplicatedMatch(f,paramToMatch))
                       );
2
Andiih

ここにたくさんの選択肢があります。 LINQとStringBuilderを使用すると、次のようなパフォーマンスが得られます。

StringBuilder builder = new StringBuilder();
List<string> MyList = new List<string>() {"one","two","three"};

MyList.ForEach(w => builder.Append(builder.Length > 0 ? ", " + w : w));
return builder.ToString();
1
Kelly

Linqを使用してIISログファイルを解析するとき、私は次のことをすばやく実行しました。2百万行を試行するとメモリ不足エラーが発生しましたが、100万行でかなりうまく動作しました。

    static void Main(string[] args)
    {

        Debug.WriteLine(DateTime.Now.ToString() + " entering main");

        // USED THIS DOS COMMAND TO GET ALL THE DAILY FILES INTO A SINGLE FILE: copy *.log target.log 
        string[] lines = File.ReadAllLines(@"C:\Log File Analysis\12-8 E5.log");

        Debug.WriteLine(lines.Count().ToString());

        string[] a = lines.Where(x => !x.StartsWith("#Software:") &&
                                      !x.StartsWith("#Version:") &&
                                      !x.StartsWith("#Date:") &&
                                      !x.StartsWith("#Fields:") &&
                                      !x.Contains("_vti_") &&
                                      !x.Contains("/c$") &&
                                      !x.Contains("/favicon.ico") &&
                                      !x.Contains("/ - 80")
                                 ).ToArray();

        Debug.WriteLine(a.Count().ToString());

        string[] b = a
                    .Select(l => l.Split(' '))
                    .Select(words => string.Join(",", words))
                    .ToArray()
                    ;

        System.IO.File.WriteAllLines(@"C:\Log File Analysis\12-8 E5.csv", b);

        Debug.WriteLine(DateTime.Now.ToString() + " leaving main");

    }

私がlinqを使った本当の理由は、以前に必要だったDistinct()のためでした。

string[] b = a
    .Select(l => l.Split(' '))
    .Where(l => l.Length > 11)
    .Select(words => string.Format("{0},{1}",
        words[6].ToUpper(), // virtual dir / service
        words[10]) // client ip
    ).Distinct().ToArray()
    ;
1
Andy S.

私は少し前にブログについてブログしました。

http://ondevelopment.blogspot.com/2009/02/string-concatenation-made-easy.html

ブログの投稿で、IEnumerable上で動作し、Concatenateという名前の拡張メソッドをどのように実装するかを説明します。

var sequence = new string[] { "foo", "bar" };
string result = sequence.Concatenate();

またはもっと複雑なものが好き:

var methodNames = typeof(IFoo).GetMethods().Select(x => x.Name);
string result = methodNames.Concatenate(", ");
0
Patrik Hägne