给定一个数组和另外两个数组,我需要找到第一个数组中的元素范围
例如MainArray = {2,4,6,5,8,9},range1 = {4,5,6},range2 = {6,9,8}
for First-Iteration我必须在MainArray中选择范围[4,6]中的元素 - > [4,6,5] - [3]是输出
for second-Iteration我必须在范围[5,9]中选择MainArray中的元素 - > [5,8,9] - [3]是输出
for third-Iteration我必须在MainArray中选择范围[6,8]中的元素 - > [6,8] - [2]是输出
数组返回[3,3,2]
static void Main(string[] args)
{
var rng = new Random();
var result = processFunc(Enumerable.Range(0, 5000000).OrderBy(x => rng.Next()).ToArray(),
Enumerable.Range(0, 20000).OrderBy(x => rng.Next()).Take(200).ToArray(),
Enumerable.Range(0, 20000).OrderBy(x => rng.Next()).Take(200).ToArray());
}
public static int[] processFunc(int[] scores,int[] l,int[] r)
{
IList<int> output = new List<int>();
for (int i = 0; i < l.Length; i++)
{
var bestMatch = scores.Where(x => x >= l[i] && x <= r[i]);
output.Add(bestMatch.Count());
}
return output.ToArray();
}
当数字很小时代码运行正常但是一旦它们> 50,000,程序就会变慢。如何优化此解决方案?
答案 0 :(得分:2)
假设l
和r
具有相同的长度,请考虑以下方法:
public static int[] processFunc(int[] scores, int[] l, int[] r)
{
var min = Math.Min(l.Min(z => z), r.Min(z => z));
var max = Math.Max(l.Max(z => z), r.Max(z => z));
var grouped = scores.Where(z => z >= min && z <= max).GroupBy(z => z).Select(val => Tuple.Create(val.Key, val.Count())).OrderBy(z => z.Item1).ToList();
return l.Zip(r, (left, right) =>
{
var matching = grouped.Where(z => z.Item1 >= left).TakeWhile(z => z.Item1 <= right);
return matching.Sum(z => z.Item2);
}).ToArray();
}
min
和max
用于忽略不相关(太大或太小)的数字。 grouped
用于预先计算计数并按顺序排列。 Zip
用于排列l
和r
值并将计数汇总在一起。
这个解决方案在我的机器上比原始代码快大约2-3倍(剩下的大部分时间实际上是设置参数,而不是在函数本身中。)