C# 使用最后一个元素扩展列表,以匹配LINQ zip中较长的列表

C# 使用最后一个元素扩展列表,以匹配LINQ zip中较长的列表,c#,linq,list,haskell,f#,C#,Linq,List,Haskell,F#,我有两个收藏: p = [ a, b ] v = [ 1, 2, 3, 4, 5 ] 我想处理以下元组: [ [a,1], [b,2], [b,3], [b,4], [b,5] ] 我目前的代码是: p.zip(v, (x,y) => { ... }) 但我当然只会处理: [ [a,1], [b,2] ] 感觉就像我想要创建一个无限的last(p)列表,上面覆盖着p,然后用v压缩。比如: extend(p).zip( v, ... ) var almostInfinite = i

我有两个收藏:

p = [ a, b ]
v = [ 1, 2, 3, 4, 5 ]
我想处理以下元组:

[ [a,1], [b,2], [b,3], [b,4], [b,5] ]
我目前的代码是:

p.zip(v, (x,y) => { ... })
但我当然只会处理:

[ [a,1], [b,2] ]
感觉就像我想要创建一个无限的last(p)列表,上面覆盖着p,然后用v压缩。比如:

extend(p).zip( v, ... )
var almostInfinite = items.Concat(Enumerable.Repeat(items.Last(), Int32.MaxValue));
其中extend(IEnumerable list)返回

我想我可以将extend()写为列表上的枚举数,当耗尽时,它会无限地返回最后一个元素

我想知道的是,是否有一种通过组合现有函数来创建extend的函数方法。我很高兴看到它用Haskell/F#表示,即使那些函数在LINQ中不存在。我鼓励自己从功能上思考

我已经找遍了可能的原子,但没有看到任何可能产生我所需要的东西

谢谢大家!

编辑:

我进一步减少了这个问题:

extend(list) = list.Concat( repeat(list.Last()) )

where repeat(T item) returns [ item, item, ..., item ]
我现在正在搜索LINQ和Haskell,查找Haskell(ghci)中类似“repeat”的现有实现

然后

使用Linq可以创建扩展

public static class Extensions {
    public static IEnumerable<A> extend<A>(this IEnumerable<A> a, int count) {
        return a.Concat(Enumerable.Range(0, Math.Max(0, count - a.Count())).Select(_ => a.Last()));
    }
    public static IEnumerable<Tuple<A, B>> zipExtendingBoth<A, B>(this IEnumerable<A> a, IEnumerable<B> b) {
        if(!a.Any() || !b.Any())
            return new Tuple<A, B> [] { };
        return a.extend(b.Count()).Zip(b.extend(a.Count()), Tuple.Create);
    }
}
结果

A, 1
B, 2
C, 3
C, 4
C, 5
如果你的“正确”列表是无限的(首先不能),那么

公共静态类扩展{
公共静态IEnumerable zipWithInfinite(此IEnumerable a,IEnumerable b){
如果(!a.Any()| |!b.Any())
返回新元组[]{};
var max_a_index=a.Count()-1;
返回b.Select((x,i)=>Tuple.Create(a.ElementAt(Math.Min(i,max_a_index)),x));
}
}

您提到的功能
repeat
可以按如下方式实现:

let repeat item = 
    Seq.initInfinite (fun _ -> item)
留在.Net/C世界:

您可以使用以下内容:

extend(p).zip( v, ... )
var almostInfinite = items.Concat(Enumerable.Repeat(items.Last(), Int32.MaxValue));
但它不会产生一个真正无限的序列

编写自己的
Extend
方法也不难:

IEnumerable<T> Extend<T>(IEnumerable<T> source)
{
    // error checking omitted 
    var e = source.GetEnumerator();
    T last = default(T);
    while(e.MoveNext())
        yield return last = e.Current;
    while(true)
        yield return last;
}
IEnumerable扩展(IEnumerable源代码)
{
//省略错误检查
var e=source.GetEnumerator();
T last=默认值(T);
while(如MoveNext())
上次收益率=当前收益率;
while(true)
收益率最后;
}
您还可以创建另一个版本的
Zip
。看看morelinq's,它处理不同大小的源序列。

Haskell中的解决方案:

> let extend = foldr (\x xs -> x : if null xs then repeat x else xs) [] 
一些测试:

> extend []
[]
> take 10 $ extend [1]
[1,1,1,1,1,1,1,1,1,1]
> take 10 $ extend [1,2,3]
[1,2,3,3,3,3,3,3,3,3]
上面没有使用
last
,因此我们没有保存对整个输入列表的引用以
extend
——这样它就可以被垃圾收集

当然,显式递归也可以工作:

extend :: [a] -> [a]
extend []     = []
extend [x]    = repeat x
extend (x:xs) = x : extend xs

是否始终要扩展p的最后一个元素,使其与v的所有剩余元素相匹配?如果v的元素比p少呢?@HW问得好。严格地说,那件事我是分开处理的。这是一个错误条件。完整的monty解决方案将始终至少与p一样长,并为缺少的v元素提供默认值。如果能看到这一点也能实现,那就太棒了。我应该试着自己去弄清楚,但我很乐意看到指点。非常感谢。您还可以通过定义自己的zip函数来避免创建扩展列表。例如,
zlr(x:xs)[y]=(x,y):zlrxs[y];zlr(x:xs)(y:ys)=(x,y):zlr-xs-ys;zlr[].[]
有人能解释投票失败的原因吗?我没有做足够的研究吗?几乎无限满足要求,谢谢!我们有类似的extend实现,但如果源代码为空,我将不返回任何内容。谢谢你对morelinq的介绍。谢谢。我一直在寻找对现有函数的重用,但您的代码向我展示了如何避免使用yieldbreak,对此我非常高兴。如果v需要扩展,当p_elem是p的对应项时,使用f(p_elem)扩展v。我忘了提到这一点。我刚刚看到了你回复中的Haskell部分(是编辑吗?)-这也很简洁。谢谢,谢谢,这给了我一个在哈斯克尔探险的地方。
> let extend = foldr (\x xs -> x : if null xs then repeat x else xs) [] 
> extend []
[]
> take 10 $ extend [1]
[1,1,1,1,1,1,1,1,1,1]
> take 10 $ extend [1,2,3]
[1,2,3,3,3,3,3,3,3,3]
extend :: [a] -> [a]
extend []     = []
extend [x]    = repeat x
extend (x:xs) = x : extend xs