2014-11-05 113 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