我有这样一个列表:
public static List<int[]> list = new List<int[]>();
另外我还有一个名为X的变量.X可以取任何值。我想在list[?][1]
中找到与X最接近和较小的值。例如:
如果X是1300,我想取列表索引:1。或者如果X是700,我想取索引:0。我怎么能通过linq做到这一点?或者,还有其他解决方案吗?
提前致谢。
答案 0 :(得分:4)
您可以通过以下方式执行此操作(代码段假设,该列表不为空)
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
答案 1 :(得分:1)
我知道您要求Linq解决方案,但我认为非Linq解决方案也很好。
如果您对非Linq解决方案感兴趣,可以选择其中一个( 在一个地方使用Linq,但实际上,这一点非常重要!)。< / p>
感兴趣的主要方法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);
}
}
}
答案 2 :(得分:0)
您可以从将元素展平为新的匿名类型开始,其中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)}));
现在你可以找到最佳的delta:
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();
但我倾向于发现其他解决方案更具可读性。