2014-02-28 28 views
0

我正在尝试使用LINQ来转换以下列表。只要产品小于15,LINQ应该将每个元素与下一个元素相乘。此外,我们应该节省用于形成产品的元素数量。使用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)来完成的。

使用“正常”方法的一个显而易见的问题是,您很快就会发现自己使用超出最大允许数字的数字。你可以通过使用旧的分而治之的方法和自然对数函数的一些帮助来解决这个问题。

+1

你有什么特别的理由需要使用LINQ吗?似乎你可以轻松实现这一点,只是通过阵列。 –

回答

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

我不觉得有什么样构建成标准的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

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