Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/314.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/arrays/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/php/288.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 通过检查元素上的条件将列表拆分为子列表_C#_Arrays_Linq_List_Functional Programming - Fatal编程技术网

C# 通过检查元素上的条件将列表拆分为子列表

C# 通过检查元素上的条件将列表拆分为子列表,c#,arrays,linq,list,functional-programming,C#,Arrays,Linq,List,Functional Programming,假设我有一个整数数组,我想把它分成几个部分,我想用零作为何时中断的条件。类似这样的内容: [1,2,3,0,4,5,0,6,7] => [[1,2,3,0], [4,5,0], [6,7]] 嗯,使用两个for循环可以很容易地完成,但我想知道是否可以使用LINQ来完成这项工作。 有几个问题是这样的,但与此相反,它们依赖于列表之外提供的条件。 注意:我知道在一个线程中问一个以上的问题是不礼貌的,但是如果有人熟悉函数式编程(因为本质上,这确实是一个FP问题),我也希望看到他们的观点和可能的

假设我有一个整数数组,我想把它分成几个部分,我想用零作为何时中断的条件。类似这样的内容:

[1,2,3,0,4,5,0,6,7] => [[1,2,3,0], [4,5,0], [6,7]]
嗯,使用两个for循环可以很容易地完成,但我想知道是否可以使用LINQ来完成这项工作。

有几个问题是这样的,但与此相反,它们依赖于列表之外提供的条件。


注意:我知道在一个线程中问一个以上的问题是不礼貌的,但是如果有人熟悉函数式编程(因为本质上,这确实是一个FP问题),我也希望看到他们的观点和可能的解决方案。这里有一个扩展,可以帮助:

public static IEnumerable<Tuple<TIn, int>> MarkWithLabels<TIn>(this IEnumerable<TIn> src, Predicate<TIn> splittingCondition)
{
    int label = 0;
    foreach (TIn item in src)
    {
        yield return new Tuple<TIn, int>(item, label);
        if (splittingCondition(item))
            label++;
    }
}

FP解决方案可能基本相同,但foreach除外。

您的集合中的不同元素之间存在依赖关系,具体来说,对于您想知道的每个元素,“前一个元素是零吗?”。只要您的查询依赖于上一个元素(或者更一般地说,只要您的查询依赖于相同序列的其他元素),您就应该使用
Aggregate
(或者在更一般的函数编程术语中,
fold
)。这是因为与其他LINQ运算符不同,
Aggregate
,允许您将状态从一个迭代带到下一个迭代

因此,为了回答您的问题,我将在LINQ中编写以下查询

// assume our list of integers it called values
var splitByZero = values.Aggregate(new List<List<int>>{new List<int>()},
                                   (list, value) => {
                                       list.Last().Add(value);
                                       if (value == 0) list.Add(new List<int>());
                                       return list;
                                   });

再次,查看lambda表达式的签名(即
Func),我编译了两个完全基于答案的扩展方法

公共静态IEnumerable SplitBefore(此IEnumerable源,Func谓词)
{
返回源。聚合(
可枚举。重复(新列表(),1),
(列表,值)=>
{
if(谓词(值))
list=list.Concat(Enumerable.Repeat(newlist(),1));
list.Last().Add(值);
退货清单;
}
)
.Where(list=>list.Any());
}
公共静态IEnumerable SplitAfter(此IEnumerable源,Func谓词)
{
返回源。聚合(
可枚举。重复(新列表(),1),
(列表,值)=>
{
list.Last().Add(值);
返回谓词(值)
?list.Concat(可枚举。重复(新列表(),1))
:列表;
}
)
.Where(list=>list.Any());
}

不幸的是,
IEnumerable
版本不起作用,因为
.Concat()
不会像
那样改变调用对象。Add()
会改变调用对象,因为该行没有
返回什么都不做,结果总是空的。很多可枚举的空。为了解决这个问题,同时又不使事情太复杂,我决定构建
IEnumerable
,使用
.Add()
作为值,使用
.Concat()
作为拆分列表。谢谢你的回答,这是最有洞察力的。
// assume our list of integers it called values
var splitByZero = values.Aggregate(new List<List<int>>{new List<int>()},
                                   (list, value) => {
                                       list.Last().Add(value);
                                       if (value == 0) list.Add(new List<int>());
                                       return list;
                                   });
values.Aggregate(new List<List<int>>{new List<int>()},
(list, value) => {...}
list.Last().Add(value);
if (value == 0) list.Add(new List<int>());
return list;
public static IEnumerable<IEnumerable<T>> SplitOn<T>(this IEnumerable<T> source, Func<T, bool> predicate)
{
    return source.Aggregate(new List<List<T>> {new List<T>()},
                            (list, value) =>
                                {
                                    list.Last().Add(value);
                                    if (predicate(value)) list.Add(new List<T>());
                                    return list;
                                });
}
public static IEnumerable<IEnumerable<T>> SplitOn<T>(this IEnumerable<T> source, Func<T, bool> predicate)
{
    return source.Aggregate(Enumerable.Repeat(Enumerable.Empty<T>(), 1),
                            (list, value) =>
                                {
                                    list.Last().Concat(Enumerable.Repeat(value, 1));
                                    return predicate(value) ? list.Concat(Enumerable.Repeat(Enumerable.Empty<T>(), 1)) : list;
                                });
}
public static IEnumerable<List<T>> SplitBefore<T>(this IEnumerable<T> source, Func<T, bool> predicate)
{
    return source.Aggregate(
        Enumerable.Repeat(new List<T>(), 1),
        (list, value) =>
        {
            if (predicate(value))
                list = list.Concat(Enumerable.Repeat(new List<T>(), 1));
            list.Last().Add(value);
            return list;
        }
    )
    .Where(list => list.Any());
}


public static IEnumerable<List<T>> SplitAfter<T>(this IEnumerable<T> source, Func<T, bool> predicate)
{
    return source.Aggregate(
        Enumerable.Repeat(new List<T>(), 1),
        (list, value) =>
        {
            list.Last().Add(value);
            return predicate(value)
                ? list.Concat(Enumerable.Repeat(new List<T>(), 1))
                : list;
        }
    )
    .Where(list => list.Any());
}