2016-12-03 54 views
2

我想分割列表就像string.split(split_between_that_value)那樣,我該怎麼做?分割列表就像string.split()

所以用字符串"some string with spaces" string.Split('')會將它拆分爲[some, string, with, spaces]數組。

但是隨着含作爲項目我不知道如何做到這一點的所有字符列表...

列表:

{'s','o','m','e',' ','s','t','r','i','n','g',' ','w','i','t','h',' ','s','p','a','c','e','s'}

我希望它分裂成列表的列表:

{{'s','o','m','e'},{'s','t','r','i','n','g'},{'w','i','t','h'},{'s','p','a','c','e','s'}}

+0

是List列表? –

+0

@ robert-m沒有我的列表是列表 BladeMight

回答

2

有趣的是,還沒有一種現有的擴展方法可以實現這一點的盒子。

public static class EnumerableExtensions 
{ 
    public static IEnumerable<IList<TSource>> Split<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate) 
    { 
     var list = new List<TSource>(); 

     foreach (var element in source) 
     { 
      if (predicate(element)) 
      { 
       if (list.Count > 0) 
       { 
        yield return list; 
        list = new List<TSource>(); 
       } 
      } 
      else 
      { 
       list.Add(element); 
      } 
     } 

     if (list.Count > 0) 
     { 
      yield return list; 
     } 
    } 
} 

你會這樣稱呼它:

var list = new List<char>(){'s','o','m','e',' ','s','t','r','i','n','g',' ','w','i','t','h',' ','s','p','a','c','e','s'}; 
list.Split(x => x == ' ') 
+0

我很確定這個可以使用本地LINQ完成。 – BladeMight

+0

看看這個問題將列表拆分成列表。看起來你可以使用純LINQ來完成它,但它可能沒有那麼高效。 http://stackoverflow.com/questions/13845650/use-linq-to-convert-a-list-to-a-list-of-lists –

+0

@BladeMight最後一個'if(list.Count> 0)'使它與''a「中的'string.Split'行爲相比有點不一致.Split'返回與'」a「.Split'相同的結果。我會刪除它以返回所有結果,或者將其添加到'yield'以排除空條目。 – Slai

2

我會寫,如果你想要一個通用的解決方案(東西的不僅僅是IEnumerable<char>作品),你可以像這樣的東西自己實現像

public static IEnumerable<IEnumerable<T>> GroupWhile<T>(this IEnumerable<T> seq, 
                 Func<T, bool> condition) 
{ 
    List<T> list = new List<T>(); 
    using (var en = seq.GetEnumerator()) 
    { 
     if (en.MoveNext()) 
     { 
      list.Add(en.Current); 

      while (en.MoveNext()) 
      { 
       if (condition(en.Current)) 
       { 
        list.Add(en.Current); 
       } 
       else 
       { 
        yield return list; 
        list = new List<T>(); 
       } 
      } 

      if (list.Any()) 
       yield return list; 
     } 
    } 
} 

的擴展方法和用它作爲

var input = new[]{ 's', 'o', 'm', 'e', ' ', 's', 't', 'r', 'i', 'n', 'g', ' ', 'w', 'i', 't', 'h', ' ', 's', 'p', 'a', 'c', 'e', 's' }; 
var result = input.GroupWhile(x => x != ' ') 
      .ToList(); 
-1

我的猜測是,你可能會尋找這樣的事情:

List<char> list = "some string with spaces".ToList(); 

List<List<char>> lists = list.Aggregate(new List<List<char>>() { new List<char>() }, 
    (a, e) => { if (e == ' ') a.Add(new List<char>()); else a.Last().Add(e); return a; }); 

我希望這是隻是一點點比延遲執行速度更快yield答案,但一些List<T>.Add額外的內存分配的可避免與 List<T>.GetRangeList<T>.CopyTo

static List<List<T>> spliT<T>(this List<T> list, T separator = default(T), int start = 0) 
{ 
    var lists = new List<List<T>>(); 

    for (int i = start; i < list.Count; i++) 
     if (list[i].Equals(separator)) 
     { 
      lists.Add(list.GetRange(start, i - start)); 
      start = i + 1; 
     } 

    lists.Add(list.GetRange(start, list.Count - start)); 
    return lists; 
} 
+0

你爲什麼會'期望這比延遲執行'yield' answers'快一點?你能否詳細說明,因爲我沒有任何理由認爲是這樣。這兩種解決方案都有同樣的問題。他們急切地加載源數據。你不知道源數據是什麼,你不知道它是否適合內存。如果您的擴展方法的使用者只是打算「拿」第一個'n'元素,會怎樣?你的方法仍然會生成整個列表。 –

+0

由於「我希望它分裂成列表清單:」,這將更接近於string.Split行爲。我的猜測是,'.ToList'將用於你的擴展中以獲得所需的結果,所以我最初的原因是「在延遲執行時使用'.ToList'快於yield'答案」,但在發佈之前縮短了它。 – Slai

+0

我沒有投票的方式。 –