2014-11-05 108 views
3

我有一个列表如下:查找数组中最接近的值与linq列表?

public static List<int[]> list = new List<int[]>(); 

enter image description here

另外我也有一个变量命名为X,X可以采取任何价值。我想在list[?][1]中找到与X最接近和最小的值。例如:

如果X是1300,我想要列表索引:1.或者如果X是700,我想采取索引:0.我怎样才能通过linq做到这一点?或者,还有其他解决方案吗?

在此先感谢。

+0

它是什么你想要返回?索引?价值? – flindeberg 2014-11-05 09:06:02

+0

(1)是否必须使用Linq? (2)正如弗林德伯格所问,你想要返回什么?内部列表?内部列表+该列表中找到的元素的索引?外部列表索引+该列表中找到的元素的内部列表索引?或者是其他东西? – 2014-11-05 09:22:20

+0

我想取最接近X值的变量索引。正如我的问题,如果X = 700,结果应该是0.因为480是最接近和较小的值,并且它的列表索引是0. – 1teamsah 2014-11-05 10:49:42

回答

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 
+0

感谢您的关注。然而,它发现最接近的价值,但不小。例如:X = 3889,列表[7] [1] = 3630,列表[8] [1] = 4080.所以,查询找到8.但它应该是7.我能为此做些什么? – 1teamsah 2014-11-05 09:10:13

+0

@ team16sah是的,我没有注意到 - 请现在检查(编辑后) – 2014-11-05 09:11:04

+1

事实上,代码似乎只在数组中的值从最小排序到最大时才起作用。 – madd0 2014-11-05 09:15:28

0

你就可以开始通过扁平化的元素以新的匿名类型,其中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(); 

但我倾向于发现其他解决方案更具可读性。

1

我知道你问了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); 
     } 
    } 
} 
+0

用于清洁代码。 Linq解决方案非常难以维护,难以理解,这不是linq的地方。 – 2014-11-05 14:21:54