如何分裂一个通用数组
本文关键字:一个 数组 分裂 何分裂 | 更新日期: 2023-09-27 18:07:56
我想模仿字符串。泛型数组的拆分功能。
我已经想出了这个方法,它似乎对双精度对象有效。
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();
}
那么,我有三个问题:
- 有没有更好的/通用的c#方法来做到这一点?
- 如何让模板方法工作?(我在
vals[i] != t
上得到一个错误)-现在修复 - 我怎样才能使它更好(它现在有点丑,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]
您可以在任意序列上惰性地执行此操作,并将其作为扩展方法。我也会去掉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]
您可以使用以下通用扩展方法通过一些分隔符分割序列。它使用默认比较器来比较每个带有分隔符的项。
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();
如何让模板方法工作?(我得到一个错误在
vals[i] != t
)
!=
操作符不能为任意类型T
定义。但是,您知道T
实现了IComparable<T>
,因此可以利用它:
vals[i].CompareTo(t) != 0