2010-09-16 143 views
28

我有一個List,MyStuff具有Type Float屬性。LINQ獲取最接近的值?

有屬性值爲10,20,22,30的對象。

我需要編寫一個查詢,查找最接近21的對象,在這種情況下,它會找到20和22對象。然後,我需要寫一個發現對象關閉到21而不會超過,並將返回值爲20的對象。

我不知道在哪裏/如何從這一開始。幫幫我?

謝謝。

更新 - 哇有這麼多真棒迴應在這裏。謝謝!我不知道哪一個要遵循,所以我會嘗試一切。有一件事可能會讓這個問題變得更有趣或者更少,因爲相同的查詢將不得不適用於LINQ-to-SQL實體,所以從MS Linq論壇收穫的答案可能會最好?不知道。

+0

呃,22是21歲以上....當然會找到20嗎? – cjk 2010-09-16 11:50:52

+0

是的,我的意思是20,對於擰緊抱歉。 – Snowy 2010-09-16 15:02:22

回答

18

下面是滿足線性時間的第二個查詢的解決方案:

var pivot = 21f; 
var closestBelow = pivot - numbers.Where(n => n <= pivot) 
            .Min(n => pivot - n); 

(來自「上面」編輯,以「自下而上」的澄清之後)

至於第一個查詢,這將是最容易使用MoreLinqMinBy擴展:

var closest = numbers.MinBy(n => Math.Abs(pivot - n)); 

它也可以做到它以線性時間標準LINQ,但2次來源:

var minDistance = numbers.Min(n => Math.Abs(pivot - n)); 
var closest = numbers.First(n => Math.Abs(pivot - n) == minDistance); 

如果效率是不是一個問題,你可以排序的序列,並挑選在O(n * log n)爲OT的第一個值她已經發布。

+0

如果我們需要22而不是? – deadManN 2016-08-02 09:15:40

21

嘗試用數字和21,然後採取的第一項之差的絕對值,對它們進行排序:根據@Yuriy Faktorovich的評論

float closest = MyStuff 
    .Select (n => new { n, distance = Math.Abs (n - 21) }) 
    .OrderBy (p => p.distance) 
    .First().n; 

或縮短它:

float closest = MyStuff 
    .OrderBy(n => Math.Abs(n - 21)) 
    .First(); 
+5

您可以通過刪除「Select」並將距離放入'OrderBy'來縮短該距離。 – 2010-09-16 02:47:13

6

基於微軟Linq論壇上的this post

var numbers = new List<float> { 10f, 20f, 22f, 30f }; 
var target = 21f; 

//gets single number which is closest 
var closest = numbers.Select(n => new { n, distance = Math.Abs(n - target) }) 
    .OrderBy(p => p.distance) 
    .First().n; 

//get two closest 
var take = 2; 
var closests = numbers.Select(n => new { n, distance = Math.Abs(n - target) }) 
    .OrderBy(p => p.distance) 
    .Select(p => p.n) 
    .Take(take);  

//gets any that are within x of target 
var within = 1; 
var withins = numbers.Select(n => new { n, distance = Math.Abs(n - target) }) 
    .Where(p => p.distance <= within) 
    .Select(p => p.n); 
2
List<float> numbers = new List<float>() { 10f, 20f, 22f, 30f }; 
float pivot = 21f; 
var result = numbers.Where(x => x >= pivot).OrderBy(x => x).FirstOrDefault(); 

OR

var result = (from n in numbers 
       where n>=pivot 
       orderby n 
       select n).FirstOrDefault(); 

和這裏來擴展方法:

public static T Closest<T,TKey>(this IEnumerable<T> source, Func<T, TKey> keySelector, TKey pivot) where TKey : IComparable<TKey> 
{ 
    return source.Where(x => pivot.CompareTo(keySelector(x)) <= 0).OrderBy(keySelector).FirstOrDefault(); 
} 

用法:

var result = numbers.Closest(n => n, pivot); 
+1

您應該在'Where'後面放置'OrderBy' *,以便它不必排序儘可能多的元素。 – Gabe 2010-09-16 02:58:58

+0

@加貝 - 感謝您的建議。我修改了代碼。 – 2010-09-16 03:06:45