我有这样的1和0的列表:
var list = new List<int>{1,1,1,0,1,1,0,1,1,1,1,0,1,1,1,1,1,1,0,1,1,1,0,1}
两个项目之间,只能是一个零。 如何将该列表拆分为0的子列表?
换句话说:如果我有这样的字符串:string myString = "111011011110111111011101"
那么很容易将它分成0个字符串。
但如何用列表来做呢?这个例子shoudl产生这些子列表:
1,1,1
1,1
1,1,1,1
1,1,1,1,1,1
1,1,1
1
那么有没有更好的方法然后将每个元素转换为字符串,加入它们并做我展示可以用字符串做什么?
答案 0 :(得分:10)
您可以通过将输入序列转换为序列序列来解决您的问题,就像LINQ GroupBy
那样。但是,在您的情况下,您正在对输入序列的更改进行分组。也许有可能将现有的LINQ运算符(如GroupBy
,Zip
和Skip
组合成可以满足您需求的东西,但我认为创建迭代器更容易(并且表现更好)查看输入序列中项目对的块:
static class EnumerableExtensions {
public static IEnumerable<IEnumerable<T>> GroupOnChange<T>(
this IEnumerable<T> source,
Func<T, T, Boolean> changePredicate
) {
if (source == null)
throw new ArgumentNullException("source");
if (changePredicate == null)
throw new ArgumentNullException("changePredicate");
using (var enumerator = source.GetEnumerator()) {
if (!enumerator.MoveNext())
yield break;
var firstValue = enumerator.Current;
var currentGroup = new List<T>();
currentGroup.Add(firstValue);
while (enumerator.MoveNext()) {
var secondValue = enumerator.Current;
var change = changePredicate(firstValue, secondValue);
if (change) {
yield return currentGroup;
currentGroup = new List<T>();
}
currentGroup.Add(secondValue);
firstValue = secondValue;
}
yield return currentGroup;
}
}
}
GroupOnChange
将获取输入序列中的项目并将它们分组为一系列序列。当changePredicate
为真时,将启动一个新组。
您可以使用GroupOnChange
完全按照自己的意愿分割输入序列。然后,您必须使用Where
删除作为值为零的组。
var groups = items
.GroupOnChange((first, second) => first != second)
.Where(group => group.First() != 0);
如果输入是类实例并且您希望按该类的属性进行分组,则也可以使用此方法。然后,您必须相应地修改谓词以比较属性。 (我知道你需要这个,因为你问了一个现在删除的问题,这个问题稍微复杂一点,输入序列不仅仅是数字,而是带有数字属性的类。)
答案 1 :(得分:6)
您可以编写如下的扩展方法:
public static class Extensions
{
public static IEnumerable<IEnumerable<TSource>> Split<TSource>(this IEnumerable<TSource> source, TSource splitOn, IEqualityComparer<TSource> comparer = null)
{
if (source == null)
throw new ArgumentNullException("source");
return SplitIterator(source, splitOn, comparer);
}
private static IEnumerable<IEnumerable<TSource>> SplitIterator<TSource>(this IEnumerable<TSource> source, TSource splitOn, IEqualityComparer<TSource> comparer)
{
comparer = comparer ?? EqualityComparer<TSource>.Default;
var current = new List<TSource>();
foreach (var item in source)
{
if (comparer.Equals(item, splitOn))
{
if (current.Count > 0)
{
yield return current;
current = new List<TSource>();
}
}
else
{
current.Add(item);
}
}
if (current.Count > 0)
yield return current;
}
}
并像这样使用它:
var list = new List<int>{1,1,1,0,1,1,0,1,1,1,1,0,1,1,1,1,1,1,0,1,1,1,0,1};
var result = list.Split(0);
答案 2 :(得分:5)
int c = 0;
var list = new List<int>{1,1,1,0,1,1,0,1,1,1,1,0,1,1,1,1,1,1,0,1,1,1,0,1};
var res = list
// split in groups and set their numbers
// c is a captured variable
.Select(x=>new {Item = x, Subgroup = x==1 ? c : c++})
// remove zeros
.Where(x=>x.Item!=0)
// create groups
.GroupBy(x=>x.Subgroup)
// convert to format List<List<int>>
.Select(gr=>gr.Select(w=>w.Item).ToList())
.ToList();
答案 3 :(得分:5)
您可以按下一个零的索引进行分组:
static void Main(string[] args)
{
var list = new List<int> { 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1 };
var result = list.Select((e, i) => new { Element = e, Index = i })
.Where(e => e.Element == 1)
.GroupBy(e => list.IndexOf(0, e.Index));
}
答案 4 :(得分:3)
也许更简单:
IEnumerable<IEnumerable<int>> Split(IEnumerable<int> items)
{
List<int> result = new List<int>();
foreach (int item in items)
if (item == 0 && result.Any())
{
yield return result;
result = new List<int>();
}
else
result.Add(item);
if (result.Any())
yield return result;
}
答案 5 :(得分:3)
下面的代码通过迭代列表并存储&#39; 1&#39;的子序列来分割。在列表列表中。
X
答案 6 :(得分:0)
我最喜欢ASh的solution。我用它做了一点改动。 “ my”变体中没有捕获的变量:
var list = new List<int> { 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1 };
var res = list
// Step 1: associate every value with an index
.Select((x, i) => (Value: x, Index: i))
// Step 2: remove separator values
.Where(x => x.Value != 0)
// Step 3: adjacent items will have the same result
// subtracting real position from the index marked during the 1st step
.Select((tuple, realIndex) => (tuple.Value, GroupId: tuple.Index - realIndex))
// Step 4: group by groupId
.GroupBy(tuple => tuple.GroupId)
// Step 5: convert to List<List<int>>
.Select(group => group.Select(tuple => tuple.Value).ToList())
.ToList();
有关步骤3的更多信息
比方说,我们有5个带有索引的项目:
[ 0 1 2 3 4 ]
{ 1, 1, 0, 1, 1 }
从步骤2过滤后,数字列表如下:
[ 0 1 3 4 ]
{ 1, 1, 1, 1 }
步骤3:
real indices (ri): [ 0 1 2 3 ]
indices from the 1st step (i): [ 0 1 3 4 ]
numbers: { 1, 1, 1, 1 }
i - ri: [ 0, 0, 1, 1 ]
第4步只是按减法i - ri
(即所谓的GroupID
)的结果进行分组。