需要递归地生成文件数组的每个唯一组合
Posted
技术标签:
【中文标题】需要递归地生成文件数组的每个唯一组合【英文标题】:Need to generate every unique combination of an array of files recursively 【发布时间】:2011-04-19 00:25:39 【问题描述】:我研究并发现 很多 类似的请求,但没有什么是我需要的。
这是我的问题。我正在使用 C#,并且我有一个 FileInfo[] 数组,其中包含未知数量的元素。
FileInfo[] files = new FileInfo[]
new FileInfo(@"C:\a.jpg"),
new FileInfo(@"C:\b.jpg"),
new FileInfo(@"C:\c.jpg"),
new FileInfo(@"C:\d.jpg"),
new FileInfo(@"C:\e.jpg"),
new FileInfo(@"C:\f.jpg"),
new FileInfo(@"C:\g.jpg"),
new FileInfo(@"C:\h.jpg"),
new FileInfo(@"C:\i.jpg"),
; // Using 9 elements for this example
并且我需要生成这些文件的每个可能的重新排序组合的列表,而不是重复文件。
所以,我的一些结果会是这样的(示例不是代码格式):
a, b, c, d, e, f, g, h, i
a, b, c, d, e, f, g, i, h // i & h switched
a, b, c, d, e, f, h, g, i // last 3 elements switched
a, a, b, b, c, c, d, d, e // THIS IS NOT ACCEPTED, because elements are duplicated
以此类推,直到我想出所有可能的组合
所以结果总数应该是数组中元素数的阶乘。在这个例子中,有 9 个元素,所以应该有 9*8*7*6*5*4*3*2*1=362,880 种可能的组合。
我已经搞砸了这几天了,我就是想不通。任何帮助表示赞赏,尤其是代码示例!
谢谢!
【问题讨论】:
您想生成一个列表还是测试一个元素是否在该列表中? 您能否澄清一下,您为什么需要它?说真的,可能有比生成 350000 个 FileInfo 数组更好的解决方案。 @gaearon 呵呵呵呵,一定很真实 我确信有更好的方法。这只是我的游戏计划。在我提交了当前的帮助请求后,我决定提交大图。可以在这里找到:***.com/questions/3825387/… 【参考方案1】:使用 Linq 轻松实现:
IEnumerable<FileInfo[]> permutations =
from a in files
from b in files.Except(new[] a )
from c in files.Except(new[] a, b )
from d in files.Except(new[] a, b, c )
from e in files.Except(new[] a, b, c, d )
from f in files.Except(new[] a, b, c, d, e )
from g in files.Except(new[] a, b, c, d, e, f )
from h in files.Except(new[] a, b, c, d, e, f, g )
from i in files.Except(new[] a, b, c, d, e, f, g, h )
select new[] a, b, c, d, e, f, g, h, i ;
编辑:
这是一个通用解决方案,适用于任意数量的项目:
static class ExtensionMethods
public static IEnumerable<IEnumerable<T>> GetPermutations<T>(this IEnumerable<T> source, int count)
IEnumerable<IEnumerable<T>> result = new[] Enumerable.Empty<T>() ;
for (int i = 0; i < count; i++)
result =
from seq in result
from item in source.Except(seq)
select seq.Concat(new[] item );
return result;
如下使用:
IEnumerable<IEnumerable<FileInfo>> permutations = files.GetPermutations(9);
(这个解决方案的灵感来自Eric Lippert's article about cartesian products。)
编辑 2:
这是一个使用Aggregate
的变体:
static class ExtensionMethods
public static IEnumerable<IEnumerable<T>> GetPermutations2<T>(this IEnumerable<T> source, int count)
IEnumerable<IEnumerable<T>> seed = new[] Enumerable.Empty<T>() ;
return Enumerable.Repeat(source, count)
.Aggregate(
seed,
(accumulator, sequence) =>
from acc in accumulator
from item in sequence.Except(acc)
select acc.Concat(new[] item ));
【讨论】:
但是如果项目数不知道怎么办? 是的,我知道...我正在努力,但可能会有点困难;) 哇!感谢您的快速回复! Linq 看起来很有前途,我需要阅读它。但与此同时,由于我不太了解 Linq 的语法,我不确定您提供的是有效代码还是伪代码,并且它在我的系统上出错了。你能提供一个可行的例子吗?谢谢! @Jason,请参阅通用解决方案的更新答案。你遇到了什么错误 ?您需要使用 .NET 3.5 或更高版本,否则将无法正常工作 @Jason,这不是伪代码,我在 LINQPad 中运行它,它工作正常。它返回预期的排列数,第一个似乎是正确的(我当然没有检查所有 362880 排列...)【参考方案2】:有多种算法可用于执行此操作。下面的页面列出了 3 个不同的:
Counting And Listing All Permutations
【讨论】:
【参考方案3】:你真的想要集合的所有排列。
http://www.codeproject.com/KB/recipes/Combinatorics.aspx http://blogs.msdn.com/b/updownroundnround/archive/2009/12/14/generating-all-permutations-c-enumerator-implementation.aspx编辑:这是您正在谈论的内容的一个示例:http://www.codeproject.com/KB/recipes/Premutations.aspx
【讨论】:
以上是关于需要递归地生成文件数组的每个唯一组合的主要内容,如果未能解决你的问题,请参考以下文章