将数组拆分为数组的数组
本文关键字:数组 拆分 | 更新日期: 2023-09-27 18:16:16
有一个数组:
var arr = new int[] { 1, 1, 2, 6, 6, 7, 1, 1, 0 };
有没有一种简单的方法可以将其拆分为具有相同值的数组?
var arrs = new int[][] {
new int[] { 1, 1 },
new int[] { 2 },
new int[] { 6, 6 },
new int[] { 7 },
new int[] { 1, 1 },
new int[] { 0 } };
我更喜欢linq解决方案,但第一时间找不到。
我会为此编写一个扩展方法:
public static class SOExtensions
{
public static IEnumerable<IEnumerable<T>> GroupSequenceWhile<T>(this IEnumerable<T> seq, Func<T, T, bool> condition)
{
List<T> list = new List<T>();
using (var en = seq.GetEnumerator())
{
if (en.MoveNext())
{
var prev = en.Current;
list.Add(en.Current);
while (en.MoveNext())
{
if (condition(prev, en.Current))
{
list.Add(en.Current);
}
else
{
yield return list;
list = new List<T>();
list.Add(en.Current);
}
prev = en.Current;
}
if (list.Any())
yield return list;
}
}
}
}
并将其用作
var arr = new int[] { 1, 1, 2, 6, 6, 7, 1, 1, 0 };
var result = arr.GroupSequenceWhile((x, y) => x == y).ToList();
var grouped = arr.GroupBy(x => x).Select(x => x.ToArray())
最初没有注意到你在邻近的组之后,以下内容应该适用于该
var arr = new[] { 1, 1, 2, 6, 6, 7, 1, 1, 0 };
var groups = new List<int[]>();
for (int i = 0; i < arr.Length; i++)
{
var neighours = arr.Skip(i).TakeWhile(x => arr[i] == x).ToArray();
groups.Add(neighours);
i += neighours.Length-1;
}
实例
这将完成任务:
var arrs = arr.Select((x, index) =>
{
var ar = arr.Skip(index)
.TakeWhile(a => a == x)
.ToArray();
return ar;
}).Where((x, index) => index == 0 || arr[index - 1] != arr[index]).ToArray();
基本上,这将为每个长度为1或更大的序列项生成一个数组,并且将只选择与原始序列中的一个项相对应的数组,该项是第一个元素或与其前一个元素不同的元素。
你可以试试这个:
int index = 0;
var result = arr.Select(number =>
{
var ar = arr.Skip(index)
.TakeWhile(a => a == number)
.ToArray();
index += ar.Length;
return ar;
}).Where(x => x.Any()).ToArray();
类似@L的答案的扩展方法。B,但更注重功能:
public static IEnumerable<IEnumerable<T>> GroupWhile<T>(this IEnumerable<T> source, Func<T, T, bool> func)
{
var firstElement = source.FirstOrDefault();
return firstElement == null ? Enumerable.Empty<IEnumerable<T>>() : source.Skip(1).Aggregate(new
{
current = Tuple.Create(firstElement, ImmutableList<T>.Empty.Add(firstElement)),
results = ImmutableList<ImmutableList<T>>.Empty,
}, (acc, x) =>
func(acc.current.Item1, x)
? new { current = Tuple.Create(x, acc.current.Item2.Add(x)), results = acc.results }
: new { current = Tuple.Create(x, ImmutableList<T>.Empty.Add(x)), results = acc.results.Add(acc.current.Item2) },
x => x.results.Add(x.current.Item2).Select(r => r));
}
请注意,扩展方法使用Microsoft Immutable Collections
库。该库可以通过NuGet
下载。
用法:
var arr = new int[] { 1, 1, 2, 6, 6, 7, 1, 1, 0 };
var result = arr.GroupWhile((prev, current) => prev == current);
var printFormattedResult = result.Select((x, i) => Tuple.Create(i, string.Join(",", x)));
foreach (var array in printFormattedResult)
Console.WriteLine("Array {0} = {1}", array.Item1, array.Item2);
输出:
Array 0 = 1,1
Array 1 = 2
Array 2 = 6,6
Array 3 = 7
Array 4 = 1,1
Array 5 = 0
基准
只是为了好玩,我试着对答案进行基准测试。
我使用了以下代码:
var rnd = new Random();
var arr = Enumerable.Range(0, 100000).Select(x => rnd.Next(10)).ToArray();
var time = Stopwatch.StartNew();
var result = <answer>.ToArray();
Console.WriteLine(t.ElapsedMilliseconds);
并得到以下结果:
-------------------------------------
| Solution Time(ms) Complexity |
------------------------------------|
| L.B | 3ms | O(n) |
|-----------------------------------|
|´ebb | 41ms | O(n) |
|-----------------------------------|
| James | 137ms | O(n^2) |
|-----------------------------------|
| Robert S. | 155ms | O(n^2) |
|-----------------------------------|
| Selman22 | 155ms | O(n^2) |
-------------------------------------
我的解决方案带来的轻微时间开销(41ms(是由于使用了不可变的集合。在ex.List<T>
中添加一个项会修改List<T>
对象。-向ImmutableList<T>
中添加一个项目会克隆其中的当前元素,并将它们与新项目一起添加到新的ImmutableList<T>
中(这会导致轻微的开销(。