说我有一个整数列表:
List<int> myInts = new List<int>() {1,2,3,5,8,13,21};
我想获得下一个可用的整数,通过增加整数排序。 不是最后或最高的国家之一,但在这种情况下,下一个整数,是不是在这个列表中。 在这种情况下的数量是4。
是否有一个LINQ声明说会给我这个? 如:
var nextAvailable = myInts.SomeCoolLinqMethod();
编辑:废话。 我说,答案应该是2,但我的意思是4。我对此表示道歉!
例如:假设你是负责分发进程ID。 你想得到当前进程ID列表,并发出下一个,但未来不应该只是为最高的值加一。 相反,它应该可以从进程ID的有序列表中的下一个。 你可以得到下一个可用的开始是最高的,它其实并不重要。
Answer 1:
public static class IntExtensions
{
public static int? SomeCoolLinqMethod(this IEnumerable<int> ints)
{
int counter = ints.Count() > 0 ? ints.First() : -1;
while (counter < int.MaxValue)
{
if (!ints.Contains(++counter)) return counter;
}
return null;
}
}
用法:
var nextAvailable = myInts.SomeCoolLinqMethod();
Answer 2:
我看到很多是编写自定义扩展方法的答案,但可以与标准的LINQ扩展方法和静态解决这个问题可枚举类:
List<int> myInts = new List<int>() {1,2,3,5,8,13,21};
// This will set firstAvailable to 4.
int firstAvailable = Enumerable.Range(1, Int32.MaxValue).Except(myInts).First();
Answer 3:
通过@Kevin提供的答案有一个不良的性能配置。 该逻辑将访问源序列多次:一次用于.Count
呼叫,一旦为.FirstOrDefault
呼叫,并且每进行一次.Contains
呼叫。 如果IEnumerable<int>
实例是一个延迟序列,诸如一个的结果.Select
呼叫,这将导致至少2点计算该序列的,具有一次为每个号码。 即使你传递一个列表的方法,这将有可能经历的每个检查到的数量整个列表。 试想一下,在序列运行它{ 1, 1000000 }
,你可以看到它不会表现良好。
LINQ致力于迭代源序列不超过一次。 这是一般的可能,并可以对你的代码的性能有很大的影响。 下面是一个扩展方法,会遍历序列一次。 它通过寻找每个连续对之间的差,然后添加1到第一下数是大于1远离下一个编号:
public static int? FirstMissing(this IEnumerable<int> numbers)
{
int? priorNumber = null;
foreach(var number in numbers.OrderBy(n => n))
{
var difference = number - priorNumber;
if(difference != null && difference > 1)
{
return priorNumber + 1;
}
priorNumber = number;
}
return priorNumber == null ? (int?) null : priorNumber + 1;
}
由于这种扩展方法可以在整数的任意序列被调用,我们要确保对它们进行排序,我们遍历之前。 然后,我们计算出当前号码和先前数之间的差异。 如果这是在列表中的第一个数字, priorNumber
将是无效,因此difference
将是无效的。 如果这不是在列表中的第一个数字,我们检查,看看是否与现有数之差正好是1,如果没有,我们知道还有一定的差距,我们可以添加1现有数量。
您可以调整return语句来处理序列0或1个项目,您看合适; 我选择用于序列空序列和n + 1返回null { n }
Answer 4:
这将是相当有效:
static int Next(this IEnumerable<int> source)
{
int? last = null;
foreach (var next in source.OrderBy(_ => _))
{
if (last.HasValue && last.Value + 1 != next)
{
return last.Value + 1;
}
last = next;
}
return last.HasValue ? last.Value + 1 : Int32.MaxValue;
}
Answer 5:
好吧,这里是我想出了对我的作品的解决方案。
var nextAvailableInteger = Enumerable.Range(myInts.Min(),myInts.Max()).FirstOrDefault( r=> !myInts.Contains(r));
如果任何人有一个更优雅的解决方案,我会很乐意接受的。 但现在,这就是我把我的代码和移动上。
编辑:这是我凯文的建议添加一个扩展方法后实施。 这是真正的答案 - 没有任何一个LINQ的扩展会做这样更有意义加我自己。 这真的是我一直在寻找。
public static int NextAvailableInteger(this IEnumerable<int> ints)
{
return NextAvailableInteger(ints, 1); // by default we use one
}
public static int NextAvailableInteger(this IEnumerable<int> ints, int defaultValue)
{
if (ints == null || ints.Count() == 0) return defaultValue;
var ordered = ints.OrderBy(v => v);
int counter = ints.Min();
int max = ints.Max();
while (counter < max)
{
if (!ordered.Contains(++counter)) return counter;
}
return (++counter);
}
Answer 6:
不知道这是否有资格作为一个很酷的LINQ的方法,但使用左外连接的想法从这个SO回答
var thelist = new List<int> {1,2,3,4,5,100,101};
var nextAvailable = (from curr in thelist
join next in thelist
on curr + 1 equals next into g
from newlist in g.DefaultIfEmpty()
where !g.Any ()
orderby curr
select curr + 1).First();
这使处理上的SQL Server端,如果你使用LINQ to SQL中,并允许您不必从服务器到存储拉动ID列表。
文章来源: get next available integer using LINQ