[英]Find closest value in an array List with linq?
我有这样一个列表:
public static List<int[]> list = new List<int[]>();
另外我还有一个名为X的变量.X可以取任何值。 我想在list[?][1]
找到与X最接近和较小的值。 例如:
如果X是1300,我想取列表索引:1。或者如果X是700,我想取索引:0。我怎么能通过linq做到这一点? 或者,还有其他解决方案吗?
提前致谢。
您可以通过以下方式执行此操作(代码段假设,该列表不为空)
var x = 700;
var result = list.Select((subList, idx) => new { Value = subList[1], Idx = idx })
.Where(elem => elem.Value < x)
.Select(elem => new { Diff = Math.Abs(x - elem.Value), elem.Idx })
.OrderBy(elem => elem.Diff).FirstOrDefault();
if (result != null)
{
return result.Idx;
}
// case - there is no such index
我知道你要求Linq解决方案,但我认为非Linq解决方案也很好。
如果你对非Linq解决方案感兴趣,那么就是一个(它确实在一个地方使用了Linq,但实际上这是非常重要的!)。
感兴趣的主要方法FindClosestSmaller()
返回一个Tuple
,其中.Item1
是外部列表的索引,它包含小于或等于目标值的最接近的值,而.Item2
是该匹配的索引。内部数组。
如果未找到小于或等于目标值的值,则.Item1
和.Item2
都将为零。
请注意, FindClosestSmaller()
接受IEnumerable<IEnumerable<int>>
类型的参数,这意味着您可以将它与大多数集合类型一起使用,并且您不仅限于List<int[]>
。
using System;
using System.Collections.Generic;
using System.Linq;
namespace Demo
{
public static class Program
{
private static void Main()
{
var ints1 = new [] { 1, 480, 749, 270 };
var ints2 = new [] { 1, 810, 1080, 271 };
var ints3 = new [] { 1, 7680, 7949, 271 };
var intLists = new List<int[]> {ints1, ints2, ints3};
test(intLists, 1300);
test(intLists, 700);
test(intLists, 480);
test(intLists, 0);
}
private static void test(List<int[]> values, int target)
{
var result = FindClosestSmaller(values, target);
Console.WriteLine("Target {0} found: Outer index = {1}, Inner index = {2}", target, result.Item1, result.Item2);
}
public static Tuple<int, int> FindClosestSmaller(IEnumerable<IEnumerable<int>> sequences, int target)
{
int closest = int.MaxValue;
int closestInner = 0; // Setting these to zero means we take the first element of the
int closestOuter = 0; // first list if no smaller element is found.
int outer = 0;
foreach (var sequence in sequences)
{
int inner = 0;
foreach (int distance in sequence.Select(value => target - value))
{
if ((distance >= 0) && (distance < closest))
{
closest = distance;
closestInner = inner;
closestOuter = outer;
}
++inner;
}
++outer;
}
return new Tuple<int, int>(closestOuter, closestInner);
}
}
}
您可以从将元素展平为新的匿名类型开始,其中index
是外部数组中的索引,item是内部数组中的值:
假设输入和期望的目标值:
var target = 20;
var input = (new int[][]{new int[]{1,2,3}, new int[]{4,7,8}, new int[]{5,4}});
然后扁平化
var tmp = input.SelectMany((x, y) => x.Select(item =>
new {index = y, item = item, delta = Math.Abs(target - item)}));
现在您可以找到最佳增量:
var bestDelta = tmp.Min(x => x.delta);
从中可以很容易地找到最佳匹配:
var result = tmp.FirstOrDefault(x => x.delta == bestDelta);
或者,如果您只是想获取索引:
var index = tmp.Where(x => x.delta == bestDelta).Select(x => x.index).First();
这可以改写为oneliner:
var result = input.SelectMany((x, y) =>
x.Select(item => new {index = y, item = item, delta = Math.Abs(target - item)}))
.OrderBy(x => x.delta).Select(x => x.index).First();
但我倾向于发现其他解决方案更具可读性。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.