我有一个列表如下:查找数组中最接近的值与linq列表?
public static List<int[]> list = new List<int[]>();
另外我也有一个变量命名为X,X可以采取任何价值。我想在list[?][1]
中找到与X最接近和最小的值。例如:
如果X是1300,我想要列表索引:1.或者如果X是700,我想采取索引:0.我怎样才能通过linq做到这一点?或者,还有其他解决方案吗?
在此先感谢。
我有一个列表如下:查找数组中最接近的值与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
你就可以开始通过扁平化的元素以新的匿名类型,其中index
是外数组索引,和产品的内阵列中的值:
假设输入和期望的目标值:
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();
但我倾向于发现其他解决方案更具可读性。
我知道你问了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);
}
}
}
用于清洁代码。 Linq解决方案非常难以维护,难以理解,这不是linq的地方。 – 2014-11-05 14:21:54
它是什么你想要返回?索引?价值? – flindeberg 2014-11-05 09:06:02
(1)是否必须使用Linq? (2)正如弗林德伯格所问,你想要返回什么?内部列表?内部列表+该列表中找到的元素的索引?外部列表索引+该列表中找到的元素的内部列表索引?或者是其他东西? – 2014-11-05 09:22:20
我想取最接近X值的变量索引。正如我的问题,如果X = 700,结果应该是0.因为480是最接近和较小的值,并且它的列表索引是0. – 1teamsah 2014-11-05 10:49:42