[英]Generate number sequences with LINQ
I try to write a LINQ statement which returns me all possible combinations of numbers (I need this for a test and I was inspired by this article of Eric Lippert ). 我尝试编写一个LINQ语句,它返回所有可能的数字组合(我需要这个测试,我的灵感来自Eric Lippert的这篇文章 )。 The method's prototype I call looks like: 我调用的方法原型如下:
IEnumerable<Collection<int>> AllSequences( int start, int end, int size );
The rules are: 规则是:
size
所有返回的集合都有一个size
的长度 start
and end
should be used 应该使用start
和end
之间的每个数字 So calling the AllSequences( 1, 5, 3 )
should result in 10 collections, each of size 3: 所以调用AllSequences( 1, 5, 3 )
应该会产生10个集合,每个集合大小为3:
1 2 3
1 2 4
1 2 5
1 3 4
1 3 5
1 4 5
2 3 4
2 3 5
2 4 5
3 4 5
Now, somehow I'd really like to see a pure LINQ solution. 现在,不知怎的,我真的很想看到纯粹的LINQ解决方案。 I am able to write a non LINQ solution on my own, so please put no effort into a solution without LINQ. 我可以自己编写非LINQ解决方案,所以请不要在没有LINQ的情况下投入解决方案。
My tries so far ended at a point where I have to join a number with the result of a recursive call of my method - something like: 到目前为止,我的尝试已经结束,我必须加入一个数字与我的方法的递归调用的结果 - 如下所示:
return from i in Enumerable.Range( start, end - size + 1 )
select BuildCollection(i, AllSequences( i, end, size -1));
But I can't manage it to implement BuildCollection()
on a LINQ base - or even skip this method call. 但我无法管理它在LINQ基础上实现BuildCollection()
- 甚至跳过此方法调用。 Can you help me here? 你能帮帮我吗?
Enumerable.Range(1, 12)
.Select(x => (x - 1) + 1);
Think I've got it. 我想我已经知道了。
IEnumerable<List<int>> AllSequences(int start, int end, int size)
{
if (size == 0)
return Enumerable.Repeat<List<int>>(new List<int>(), 1);
return from i in Enumerable.Range(start, end - size - start + 2)
from seq in AllSequences(i + 1, end, size - 1)
select new List<int>{i}.Concat(seq).ToList();
}
Something like the following should do the job, I think. 我认为,像下面这样的事情应该可以胜任。
public static IEnumerable<IEnumerable<int>> AllSequences(int start, int end,
int size)
{
return size <= 0 ? new[] { new int[0] } :
from i in Enumerable.Range(start, end - size - start + 2)
from seq in AllSequences(i + 1, end, size - 1)
select Enumerable.Concat(new[] { i }, seq);
}
The key to the solution is the compound from
clause , which is quite handy for dealing with nested enumerables. 解决方案的关键是复合from
子句 ,这对于处理嵌套的可枚举非常方便。
Notice that I've changed the method signature slightly to IEnumerable<IEnumerable<int>>
, since this is more convenient when using (pure) LINQ. 请注意,我已将方法签名稍微更改为IEnumerable<IEnumerable<int>>
,因为使用(纯)LINQ时更方便。 You can always convert it easily to a IEnumerable<ICollection<int>>
at the end if you like, however. 但是,如果您愿意,可以随时将其轻松转换为IEnumerable<ICollection<int>>
。
Let me know if the code needs any explanation, but I'm hoping the LINQ syntax makes it reasonably clear. 如果代码需要任何解释,请告诉我,但我希望LINQ语法能够让它变得相当清楚。
Edit 1: Fixed bug and improved conciseness. 编辑1:修复了错误并提高了简洁性。
Edit 2: Because I'm bored and have nothing better to do (no, not really), I thought I'd write an extension method that compute the combinations of a given list of elements, making use of the AllSequences
method. 编辑2:因为我很无聊并且没有更好的事情要做(不,不是真的),我想我会编写一个扩展方法来计算给定元素列表的组合,利用AllSequences
方法。
public static IEnumerable<IEnumerable<T>> Combinations<T>(this IList<T> source,
int num)
{
return AllSequences(0, source.Count - 1, num).Select(
seq => seq.Select(i => source[i]));
}
Perhaps not the most efficient way of computing combinations, but certainly pretty compact code! 也许不是最有效的计算组合方式,但肯定是非常紧凑的代码!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.