使用last元素扩展列表以匹配LINQ zip中的更长列表

时间:2015-02-05 13:40:30

标签: 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] ]

感觉我想创建一个无限的最后一个(p)列表,用p覆盖,然后我们用v压缩。有类似的东西:

extend(p).zip( v, ... )

其中extend(IEnumerable list)返回

[ a, b, b, b, ..., b ] // Infinite/generated sequence

我认为我可以将extend()作为列表上的枚举器编写,当用尽时,不断无休止地返回最后一个元素。

我感兴趣的是,通过编写现有函数,是否存在创建扩展的功能方法。我很高兴看到它在Haskell / F#中表达,即使LINQ中不存在这些函数。我鼓励自己在功能上思考。

我已经通过https://hackage.haskell.org/package/base-4.2.0.1/docs/Data-List.html查看了可能的原子,但没有看到任何可能产生我需要的东西。

谢谢!

编辑:

我进一步减少了问题:

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

where repeat(T item) returns [ item, item, ..., item ]

我现在正在搜索LINQ和Haskell,以寻找类似“重复”的现有实现。

4 个答案:

答案 0 :(得分:4)

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

答案 1 :(得分:3)

留在.Net / C#世界:

您可以使用以下内容:

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;
}

您还可以创建另一个版本的Zip。看看morelinq的Zip,它处理不同大小的源序列。

答案 2 :(得分:2)

您提到的函数repeat可以按如下方式实现:

let repeat item = 
    Seq.initInfinite (fun _ -> item)

答案 3 :(得分:1)

在Haskell( ghci

> let p = ["A", "B", "C"]
> let v = [1..]
> let zipExtending a = zip (a ++ repeat (last a))

然后

> mapM_ print $ take 5 $ zipExtending p v
("A",1)
("B",2)
("C",3)
("C",4)
("C",5)
>

使用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);
    }
}

然后

var p = new string [] { "A", "B", "C" };
var v = Enumerable.Range(1, 5);
foreach(var e in p.zipExtendingBoth(v))
    Console.Write("{0}, {1}\n", e.Item1, e.Item2);

结果

A, 1
B, 2
C, 3
C, 4
C, 5

如果你的&#34;权利&#34;列表是无限的(首先不可能)然后

public static class Extensions {
    public static IEnumerable<Tuple<A, B>> zipWithInfinite<A, B>(this IEnumerable<A> a, IEnumerable<B> b) {
        if(!a.Any() || !b.Any())
            return new Tuple<A, B> [] { };
        var max_a_index = a.Count() - 1;
        return b.Select((x, i) => Tuple.Create(a.ElementAt(Math.Min(i, max_a_index)), x));
    }
}