我一直在解决日常编码问题,并来到了这个问题。
给出一个整数数组,返回一个新数组,使每个元素 在新数组的索引i处是所有数字的乘积 原始数组,除了i处的那个。
例如,如果我们的输入是[1、2、3、4、5],则预期输出 会是[120,60,40,30,24]。如果我们的输入是[3,2,1],则 预期输出为[2、3、6]。 后续:如果无法使用除法怎么办?
因此,执行此操作的简单方法是将数组中的所有元素相乘,然后除以[i],但这带来的问题是,如果I = 0
,您将得到一个 错误。
我知道 aggregate 函数,该函数对数组的所有成员执行操作,但是有一种方法可以修改 aggregate ,使其对< em>除一个成员外的所有成员,或者是否存在其他提供此功能的函数/方法?
答案 0 :(得分:5)
如果source
小,则可以在Where
的帮助下跳过索引,例如
int[] source = new int[] { 1, 2, 3, 4, 5 };
int[] result = Enumerable
.Range(0, source.Length)
.Select(i => source
.Where((value, index) => index != i) // all items except i-th
.Aggregate((s, a) => s * a)) // should be multiplied
.ToArray();
Console.Write(string.Join(", ", result));
结果:
120, 60, 40, 30, 24
编辑:但是,该解决方案的时间复杂度为O(N**2)
;如果初始source
数组为 large ,我们可以实现更有效的O(N)
代码(是的,我们应该注意 zeroes ):>
int[] source = ...
int[] result;
int zeroCount = source.Count(item => item == 0);
if (zeroCount >= 2) // All zeroes case
result = new int[source.Length];
else if (zeroCount == 1) // All zeroes save one value case
result = source
.Select(v => v == 0
? source.Where(item => item != 0).Aggregate((s, a) => s * a)
: 0)
.ToArray();
else { // No zeroes case
// long, 1L: to prevent integer overflow, e.g. for {1000000, 1000000} input
long total = source.Aggregate(1L, (s, a) => s * a);
result = source
.Select(v => (int)(total / v)) // yes, it's a division...
.ToArray();
}
答案 1 :(得分:3)
除了单个指定的成员(没有,是按值还是按索引指定它?)上,没有所有内建函数可以聚合。
但是,循环将非常简单,Linq为您提供了Where
方法,您可以在其中创建任意谓词,然后可以将聚合应用于过滤后的< / em>结果。
例如,要对一个数组的所有数字求和而不是对第三个数字求和,可以执行以下操作:
array.Where((x,i) => i != 2).Sum(); // use 2 since the index is 0-based
Product
也没有内置的Linq方法,但是我敢肯定那里有一个方法,否则您也可以轻松地自己动手。