假设我有这个号码列表:
List<int> = new List<int>(){3,5,8,11,12,13,14,21}
假设我想得到的最接近的数字小于11,那就是8 假设我想获得大于13的最接近的数字,即14。
列表中的数字不能重复,并且始终是有序的。我怎么能为此写Linq?
答案 0 :(得分:16)
Linq假设列表已经订购,我会这样做:
var l = new List<int>() { 3, 5, 8, 11, 12, 13, 14, 21 };
var lessThan11 = l.TakeWhile(p => p < 11).Last();
var greaterThan13 = l.SkipWhile(p => p <= 13).First();
编辑:
由于我收到了关于这个答案的负面反馈,并且为了可能会看到这个答案的人,并且虽然它被接受了但是没有进一步,我探讨了关于BinarySearch的其他评论,并决定在这里添加第二个选项(有一些小的变化)。
这是在其他地方提出的不充分的方式:
var l = new List<int>() { 3, 5, 8, 11, 12, 13, 14, 21 };
var indexLessThan11 = ~l.BinarySearch(10) -1;
var value = l[indexLessThan11];
现在上面的代码没有处理值10
实际上可能在列表中的事实(在这种情况下,不应该反转索引)!所以好的方法就是这样做:
var l = new List<int>() { 3, 5, 8, 11, 12, 13, 14, 21 };
var indexLessThan11 = l.BinarySearch(10);
if (indexLessThan11 < 0) // the value 10 wasn't found
{
indexLessThan11 = ~indexLessThan11;
indexLessThan11 -= 1;
}
var value = l[indexLessThan11];
我只想注意:
l.BinarySearch(11) == 3
//and
l.BinarySearch(10) == -4;
答案 1 :(得分:11)
使用Array.BinarySearch
- 无需LINQ或平均访问一半元素即可找到目标。
还有各种SortedXXX
类可能适合您正在进行的操作[将内置有效的O(log N)搜索]
答案 2 :(得分:5)
您可以使用二进制搜索来执行此操作。如果你搜索11,很明显你会得到你的索引。如果搜索10并使用结果的按位补码,则会得到最接近的匹配。
List<int> list = new List<int>(){3,5,8,11,12,13,14,21};
list.Sort();
int index = list.BinarySearch(10);
int found = (~index)-1;
Console.WriteLine (list[found]); // Outputs 8
同样在另一个方向搜索
int index = list.BinarySearch(15);
Console.WriteLine("Closest match : " + list[+~index]); // Outputs 21
二进制搜索也非常快。
答案 3 :(得分:4)
11以下最接近的数字:
int someNumber = 11;
List<int> list = new List<int> { 3, 5, 8, 11, 12, 13, 14, 21 };
var intermediate = from i in list
where i < someNumber
orderby i descending
select i;
var result = intermediate.FirstOrDefault();
13以上最接近的数字:
int someNumber = 13;
List<int> list = new List<int> { 3, 5, 8, 11, 12, 13, 14, 21 };
var intermediate = from i in list
where i > someNumber
orderby i
select i;
var result = intermediate.FirstOrDefault();
答案 4 :(得分:1)
这是我的回答
List<int> myList = new List<int>() { 3, 5, 8, 11, 12, 13, 14, 21 };
int n = 11;
int? smallerNumberCloseToInput = (from n1 in myList
where n1 < n
orderby n1 descending
select n1).First();
int? largerNumberCloseToInput = (from n1 in myList
where n1 > n
orderby n1 ascending
select n1).First();
答案 5 :(得分:1)
var list = new List<int> {14,2,13,11,5,8,21,12,3};
var tested = 11;
var closestGreater = list.OrderBy(n => n)
.FirstOrDefault(n => tested < n); // = 12
var closestLess = list.OrderByDescending(n => n)
.FirstOrDefault(n => tested > n); // = 8
if (closestGreater == 0)
System.Diagnostics.Debug.WriteLine(
string.Format("No number greater then {0} exists in the list", tested));
if (closestLess == 0)
System.Diagnostics.Debug.WriteLine(
string.Format("No number smaler then {0} exists in the list", tested));
答案 6 :(得分:0)
您可以使用此查询,例如:
List<int> numbers = new List<int>() { 3, 5, 8, 11, 12, 13, 14, 21 };
List<int> output = (from n in numbers
where n > 13 // or whatever
orderby n ascending //or descending
select n).ToList();
答案 7 :(得分:0)
这是我希望这对某人有帮助的方式!
List<float> list = new List<float> { 4.0f, 5.0f, 6.0f, 10.0f, 4.5f, 4.0f, 5.0f, 6.0f, 10.0f, 4.5f, 4.0f, 5.0f, 6.0f, 10.0f };
float num = 4.7f;
float closestAbove = list.Aggregate((x , y) => (x < num ? y : y < num ? x : (Math.Abs(x - num)) < Math.Abs(y - num) ? x : y));
float closestBelow = list.Aggregate((x , y) => (x > num ? y : y > num ? x : (Math.Abs(x - num)) < Math.Abs(y - num) ? x : y));
Console.WriteLine(closestAbove);
Console.WriteLine(closestBelow);
这意味着您不必订购列表
信用:改写自此处:How to get the closest number from a List<int> with LINQ?
扩展代码
float closestAboveExplained = list.Aggregate((closestAbove , next) => {
if(next < num){
return closestAbove;
}
if(closestAbove < num){
return next;
}
else{
if(Math.Abs(closestAbove - num) < Math.Abs(next - num)){
return closestAbove;
}
}
return next;
});