2013-04-05 50 views
2

我想模仿通用阵列的String.Split功能。如何拆分通用阵列

我想出了这个方法,似乎适用于双打。

public static double[][] Split(this double[] vals, double t) 
{ 
    List<double[]> ret = new List<double[]>(); 

    int last = -1; 
    for (int i = 0; i <= vals.Length; i++) 
    { 
     if (i != vals.Length && vals[i] != t) 
      continue; 

     int len = i - last - 1; 
     if (len <= 0) 
     { 
      last = i; 
      continue; 
     } 

     double[] arr = new double[len]; 
     Array.Copy(vals, last + 1, arr, 0, len); 
     last = i; 

     ret.Add(arr); 
    } 

    return ret.ToArray(); 
} 

而这其中仿制药......

public static T[][] Split<T>(this T[] vals, T t) where T : EqualityComparer<T> 
{ 
    List<T[]> ret = new List<T[]>(); 

    int last = -1; 
    for (int i = 0; i <= vals.Length; i++) 
    { 
     if (i != vals.Length && vals[i] != t) 
      continue; 

     int len = i - last - 1; 
     if (len <= 0) 
     { 
      last = i; 
      continue; 
     } 

     T[] arr = new T[len]; 
     Array.Copy(vals, last + 1, arr, 0, len); 
     last = i; 

     ret.Add(arr); 
    } 

    return ret.ToArray(); 
} 

所以,我有三个问题:

  1. 是否有这样做的更好/通用-C#的方式?
  2. 如何获取模板方法的工作? (我得到vals[i] != t错误) - 现在固定
  3. 我怎样才能做得更好(它现在是一种丑陋,IMO)

实例应用:

double[] vals = new double[] { 0, 1, 2, 0, 0, 2, 3, 0, 4, 5, 6 }; 
double[][] res = vals.Split(0); 

// res[0] = [1, 2] 
// res[1] = [2, 3] 
// res[2] = [4, 5, 6] 
+1

问题#1和#3是不是真的适合这里。他们太主题了。在codereview上它可能没问题,但它需要一些改进。它也需要先工作。 – Servy 2013-04-05 19:15:13

回答

2

您可以使用下面的通用扩展方法来通过某些分隔符分割序列。它使用默认比较器将每个项目与分隔符进行比较。

public static IEnumerable<T[]> Split<T>(this IEnumerable<T> source, T separator) 
{ 
    List<T> bucket = new List<T>(); 
    var comparer = Comparer<T>.Default; 

    foreach (var item in source) 
    { 
     if (comparer.Compare(item, separator) != 0) 
     { 
      bucket.Add(item); 
      continue; 
     } 

     if (bucket.Any()) 
     { 
      yield return bucket.ToArray(); 
      bucket = new List<T>(); 
     } 
    } 

    if (bucket.Any())   
     yield return bucket.ToArray();   
} 

用法:

double[] vals = new double[] { 0, 1, 2, 0, 0, 2, 3, 0, 4, 5, 6 }; 
double[][] res = vals.Split(0).ToArray(); 
+0

谢谢。我喜欢这个看起来/效果最好的方式。 – user807566 2013-04-05 19:43:15

2

如何我可以使用模板方法吗? (我得到vals[i] != t错误)

!=运营商不会对任何任意类型T被定义。但是,你知道,T imlements IComparable<T>,所以杠杆作用:

vals[i].CompareTo(t) != 0 
+0

如何使用'IEquatable '或'IEqualityComparer '。 – 2013-04-05 19:18:05

+0

@ p.s.w.g两者都是好主意。我专注于让他的代码工作所需的最小改变,而不是我自己如何实现它。 – Servy 2013-04-05 19:18:59

3

那么,你可以懒洋洋地做到这一点,并且在任何序列,并作为扩展方法。我也摆脱了IComparable<T>约束 - 你在这里不使用。你可能使用CompareTo,而不是试图使用!=(这可以告诉,不起作用),但因为你只对平等感兴趣,所以使用EqualityComparer<T>更有意义。

public static IEnumerable<IEnumerable<T>> Split<T>(this IEnumerable<T> source, 
                T separator) 
{ 
    List<T> currentList = new List<T>(); 
    var comparer = EqualityComparer<T>.Default; 
    foreach (var item in source) 
    { 
     if (comparer.Equals(item, separator)) 
     { 
      yield return new ReadOnlyCollection<T>(currentList); 
      currentList = new List<T>(); 
     } 
     else 
     { 
      currentList.Add(item); 
     } 
    } 
    yield return new ReadOnlyCollection<T>(currentList); 
} 

注意,这返回空的集合,如果你有任何的开始或结束,或重复分隔符的分隔符。当然,你总是可以忽略那些在主叫方:

var nonEmptySequences = original.Split(value) 
           .Where(sequence => sequence.Any()); 

短,但完整的示例代码:

using System; 
using System.Collections.Generic; 
using System.Collections.ObjectModel; 
using System.Linq; 

public static class MoreExtensions 
{ 
    public static IEnumerable<IEnumerable<T>> Split<T> 
     (this IEnumerable<T> source, T separator) 
    { 
     List<T> currentList = new List<T>(); 
     var comparer = EqualityComparer<T>.Default; 
     foreach (var item in source) 
     { 
      if (comparer.Equals(item, separator)) 
      { 
       yield return new ReadOnlyCollection<T>(currentList); 
       currentList = new List<T>(); 
      } 
      else 
      { 
       currentList.Add(item); 
      } 
     } 
     yield return new ReadOnlyCollection<T>(currentList); 
    } 

} 

class Test 
{ 
    static void Main() 
    { 
     int[] source = { 0, 1, 2, 0, 0, 2, 3, 0, 4, 5, 6 }; 
     foreach (var group in source.Split(0).Where(x => x.Any())) 
     { 
      Console.WriteLine("[{0}]", string.Join(",", group)); 
     } 
    }  
} 

输出:

[1,2] 
[2,3] 
[4,5,6] 
+0

供参考他确保没有空的条目,你不是。 – Servy 2013-04-05 19:18:10

+0

@Servy:正如我刚刚提到的:)('String.Split'不是默认情况下,并且很容易过滤出来...) – 2013-04-05 19:18:18