2

「人間が読める」データをより便利なデータ構造に解析するときによく遭遇する一般的な問題は次のとおりです。

兄弟要素のリストがあるとします。

var input = new[] {"moo", "*", "foo", "bar", "baz", "*", "roo", 
                   "moo", "*", "*", "hoot", "*", "boot"};

*は、次の区切り文字まですべての隣接する要素をグループ化する区切り文字であることを知っています。したがって、この入力に関連付けられている「より便利な」データ構造は次のとおりです。

var expectedOutput = new List<List<string>>
  {
    new List<string> {"moo"},
    new List<string> {"*", "foo", "bar", "baz"},
    new List<string> {"*", "roo", "moo"},
    new List<string> {"*"},
    new List<string> {"*", "hoot"},
    new List<string> {"*", "boot"}
  };

過去に、LINQと同様の構文を使用して、パーサーを拡張メソッドとして記述しました。

public static IEnumerable<IEnumerable<T>> GroupByDelimiter<T>(this IEnumerable<T> input, T delimiter)
{
    var currentList = new List<T>();
    foreach (T item in input)
    {
        if (!item.Equals(delimiter))
        {
            currentList.Add(item);
        }
        else
        {
            yield return currentList;
            currentList = new List<T> {item};
        }
    }

    // return the last list
    yield return currentList;
}

これは問題なく機能しますが、このメソッドGroupByDelimiterを既存のLINQ拡張メソッドを使用して書き直すことができるかどうか疑問に思いました。さらに良いことに、私が知らないいくつかのLINQメソッドがすでにこれを行っていますか?

4

1 に答える 1

1

グループ化の区切り文字として条件を使用する風変わりな方法があります。

var input = new[] {"moo", "*", "foo", "bar", "baz", "*", "roo", 
                   "moo", "*", "*", "hoot", "*", "boot"};
    int index = 0;
    var output = input.Select( x => new
                 {
                   Item=x, 
                   GroupCondition = x =="*" ? ++index:index     // Introduce GroupCondition, Increase it if delimiter is found      
                 })
          .GroupBy((x)=>x.GroupCondition)                      // Group by GroupCondition
          .Select( x => x.Select( y => y.Item));                // Get rid of GroupCondition

こちらのデモ

デモ出力

moo
* foo bar baz
* roo moo
*
* hoot
* boot
于 2013-01-09T18:50:07.977 に答える