有没有办法在功能上写这个?

时间:2014-03-17 14:57:45

标签: c# collections functional-programming

static IEnumerable<Tuple<Double, Double>> GetGreatest(List<List<Tuple<double,double>>> lst)
{
    var tempHead = lst[0][0];
    for (int i = 1; i < lst.Count; i++)
    {
        if (i != lst.Count - 1)
        { 
            var previousHead = lst[i - 1][0];
            var currentHead = lst[i][0];

            if (previousHead.Item2 != currentHead.Item1)
            {
                yield return Tuple.Create(tempHead.Item1, previousHead.Item2);
                tempHead = currentHead;
            }
        }
        else yield return Tuple.Create(tempHead.Item1, lst[i][0].Item2);
    }
}

我正在尝试以更实用的方式编写它,以便我可以更轻松地将其集成到其他语言(如Scala或F#)中的项目中,我的问题是我一直在努力使用它超过一个小时,我可以似乎把它变成了可用的东西,至少在scala中没有。

问题:我可以获得一些指示我指向正确方向的提示吗?所以我可以不让自己陷入困境......

澄清:要澄清一些关于命名等问题的混淆

这就是它的使用方式:

var lst = new List<Tuple<double,double>>{
        Tuple.Create(3.22, 3.29), Tuple.Create(3.22, 4.05), Tuple.Create(3.22, 4.12),
        Tuple.Create(3.29, 4.05), Tuple.Create(3.29, 4.12),
        Tuple.Create(4.05, 4.12),

        Tuple.Create( 9.06, 9.13),Tuple.Create( 9.06, 9.20),Tuple.Create( 9.06, 9.27),
        Tuple.Create( 9.13, 9.20),Tuple.Create( 9.13, 9.27),Tuple.Create( 9.13,10.04),
        Tuple.Create( 9.20, 9.27),Tuple.Create( 9.20,10.04),Tuple.Create( 9.20,10.11),
        Tuple.Create( 9.27,10.04),Tuple.Create( 9.27,10.11),Tuple.Create( 9.27,10.18),
        Tuple.Create(10.04,10.11),Tuple.Create(10.04,10.18),Tuple.Create(10.04,10.25),
        Tuple.Create(10.11,10.18),Tuple.Create(10.11,10.25),Tuple.Create(10.11,11.01),
        Tuple.Create(10.18,10.25),Tuple.Create(10.18,11.01),Tuple.Create(10.18,11.08),
        Tuple.Create(10.25,11.01),Tuple.Create(10.25,11.08),Tuple.Create(10.25,11.15),
        Tuple.Create(11.01,11.08),Tuple.Create(11.01,11.15),Tuple.Create(11.01,11.22),
        Tuple.Create(11.08,11.15),Tuple.Create(11.08,11.22),Tuple.Create(11.08,11.29),
        Tuple.Create(11.15,11.22),Tuple.Create(11.15,11.29),Tuple.Create(11.15,12.06),
        Tuple.Create(11.22,11.29),Tuple.Create(11.22,12.06),Tuple.Create(11.22,12.13),
        Tuple.Create(11.29,12.06),Tuple.Create(11.29,12.13),Tuple.Create(11.29,12.20),
        Tuple.Create(12.06,12.13),Tuple.Create(12.06,12.20),Tuple.Create(12.06,12.27),
        Tuple.Create(12.13,12.20),Tuple.Create(12.13,12.27),
        Tuple.Create(12.20,12.27),
};

var glist = lst.GroupBy(i => i.Item1).Select(i => i.ToList()).ToList(); // creates list of lists

var greatest = GetGreatest(glist).ToList();

最后(在本例中)将生成2个元组(3.22, 4.12)(9.06, 12.27)

从某种意义上说,在Item2中获得最大的数字

请注意,数据总是按顺序排序,因此下一项总是会比前一项大,因此无需进行比较

这个混乱的目的是获取任何非重叠数字组中的第一个和最后一个数字,所以如果你查看上面的集合,你可以看到在休息之前我有数字3.22,3.29,4.05和4.12都在元组中重叠,因为(3.22, 3.29)包含3.29,这是下面元组的第一个元素

该方法的作用是返回一个元组,其中包含元组的每个“组”中的第一个和最后一个非重叠数字

我忽略了除了子列表中的第一项之外的所有内容的原因是因为我可以看到第一个元素的Item2与下一个元素中的Item1相同(我是写下列表,使每一行对应一个子列表,使其更容易),因此没有理由包括列表的其余部分

为什么然后在你问的第一个地方包括列表的其余部分?没有我的选择......这是来自服务器的(模型)数据,它的结构如何,我真的无能为力

该程序所做的是寻找间隙,在延续中断,如果找到Item2不等于Item1的位置那么它必须意味着我们在数据中找到了一个间隙,我们可以安全地将Item1从第一个列表和Item2从差距之前的最后一个列表推送到我们想要产生的元组,从而将所有重叠数据减少到只有重要的起点和终点,删除所有中间膨胀。

1 个答案:

答案 0 :(得分:1)

您的要求似乎如下:

  1. 从每个内部元组列表中取出第一个项目;可以忽略每个内部列表中的其余项目。

  2. 将这些元组分组,而前一对的第二项等于下一项的第一个值

  3. 将每个组转换为一个元组,其中包含第一个项的第一个值和最后一个项的第二个值。

  4. 我们现在可以创建一个方法调用来执行这些单独的操作。

    static IEnumerable<Tuple<Double, Double>> GetGreatest(
        List<List<Tuple<double, double>>> list)
    {
        return list.Select(inner => inner.First())
            .GroupWhile((previous, current) => previous.Item2 == current.Item1)
            .Select(group => Tuple.Create(group.First().Item1, group.Last().Item2));
    }
    

    GroupWhile定义如下:

    public static IEnumerable<IEnumerable<T>> GroupWhile<T>(
        this IEnumerable<T> source, Func<T, T, bool> predicate)
    {
        using (var iterator = source.GetEnumerator())
        {
            if (!iterator.MoveNext())
                yield break;
    
            List<T> list = new List<T>() { iterator.Current };
    
            T previous = iterator.Current;
    
            while (iterator.MoveNext())
            {
                if (!predicate(previous, iterator.Current))
                {
                    yield return list;
                    list = new List<T>();
                }
    
                list.Add(iterator.Current);
                previous = iterator.Current;
            }
            yield return list;
        }
    }