使用linq转换此列表?

时间:2014-02-28 17:21:50

标签: linq

我正在尝试使用LINQ来转换以下列表。只要产品小于15,LINQ就应该将每个元素与下一个元素相乘。另外,我们应该保存用于构成产品的元素数量。

int[] values = { 1, 3, 4, 2, 7, 14 };  //assume Largest value will never be >= 15

1x3x4 = 12
2x7 = 14
14 = 14

{ {12,3}, {14,2}, {14,1} }

我的最终目标是获取一个非常大的数字列表的几何平均值。这通常通过将列表中的每个元素相乘(1x3x4x2x7x14)然后取第n个根(在本例中为1/6)来完成。

使用“普通”方法的一个明显问题是,您很快就会发现自己使用超出最大允许数量的数字。您可以使用旧的分而治之方法并在自然日志功能的帮助下解决此问题。

3 个答案:

答案 0 :(得分:1)

  

我的最终目标是获取一个非常大的数字列表的几何平均值。

然后只取每个数字的第n个根并随后相乘。然后您无需担心将列表拆分为组:

double mean = 1.0;
foreach(int i in values)
{
    mean *= Math.Pow(i, 1.0 / values.Length);
}

哪些可以也可以在Linq中使用Aggregate

完成
mean = values.Aggregate(1.0, (prev, i) => prev * Math.Pow(i, 1.0 / values.Length ));

答案 1 :(得分:1)

我不认为有类似的内容构建到标准的LINQ方法库中。但您可以轻松创建自己的扩展方法。我称之为AggregateUntil

public static class EnumerableExtensions
{
    public static IEnumerable<TResult> AggregateUntil<TSource, TAccumulate, TResult>(
        this IEnumerable<TSource> source,
        TAccumulate seed,
        Func<TAccumulate, TSource, TAccumulate> func,
        Func<TAccumulate, bool> condition,
        Func<TAccumulate, TResult> resultSelector
    )
    {
        TAccumulate acc = seed;
        TAccumulate newAcc;
        foreach(var item in source)
        {
            newAcc = func(acc, item);
            if(!condition(newAcc))
            {
                yield return resultSelector(acc);
                acc = func(seed, item);
            }
            else
            {
                acc = newAcc;
            }
        }
        yield return resultSelector(acc);
    }
}

现在让我们使用它。首先,只要它们符合< 15条件:

,只进行乘法运算
var grouped
    = values.AggregateUntil(1, (a,i) => a * i, a => a < 15, a => a).ToList();

返回List<int>,其中包含3个项目:121414。那就是你需要的。但现在让我们把每个乘法中聚合的项目数量。使用匿名类型::

很容易
int[] values = { 1, 3, 4, 2, 7, 14 };

var grouped
    = values.AggregateUntil(
        new { v = 1, c = 0 },
        (a, i) => new { v = a.v * i, c = a.c + 1 },
        a => a.v < 15,
        a => a).ToList(); ;

准确地返回您所需的内容:

enter image description here

答案 2 :(得分:0)

我的解决方案并不像@MarcinJuraszek那么优雅,但速度很快,它可以在你的约束下工作。

    int[] values = {1, 3, 4, 2, 7, 14};
    int product = 1;
    int elementsMultiplied = 0;
    List<Tuple<int,int>> allElements = new List<Tuple<int,int>>();
    for(int i = 0; i < values.Length ; i++)
    {
        product = product * values[i];
        elementsMultiplied++;
        if(i == values.Length - 1 || product * values[i+1] >= 15)
        {
            allElements.Add(new Tuple<int,int>(product, elementsMultiplied));
            product = 1;
            elementsMultiplied = 0;
        }
    }
    foreach(Tuple<int,int> pair in allElements)
    {
        Console.WriteLine(pair.Item1 + "," + pair.Item2);   
    }