C#代码:
static void Main(string[] args) { var arg = new List<List<int>>(); int i = 0; for (int j = 0; j < 5; j++) { arg.Add(new List<int>()); for (int j1 = i; j1 < i + 3; j1++) { //if (j1 != 5) arg[j].Add(j1); } i += 3; } List<Utils<int>.Variant<int>> b2 = new List<Utils<int>.Variant<int>>(); //int[][] bN; var s = System.Diagnostics.Stopwatch.StartNew(); //for(int j = 0; j < 10;j++) b2 = Utils<int>.Produce2(arg); s.Stop(); Console.WriteLine(s.ElapsedMilliseconds); } public class Variant<T> { public T element; public Variant<T> prevIoUs; } public static List<Variant<T>> Produce2(List<List<T>> input) { var ret = new List<Variant<T>>(); foreach (var form in input) { var newRet = new List<Variant<T>>(ret.Count * form.Count); foreach (var el in form) { if (ret.Count == 0) { newRet.Add(new Variant<T>{ element = el,prevIoUs = null }); } else { foreach (var variant in ret) { var buf = new Variant<T> { prevIoUs = variant,element = el }; newRet.Add(buf); } } } ret = newRet; } return ret; }
Scala代码:
object test { def main() { var arg = new Array[Array[Int]](5) var i = 0 var init = 0 while (i<5) { var buf = new Array[Int](3) var j = 0 while (j<3) { buf(j) = init init = init+1 j = j + 1 } arg(i)=buf i = i + 1 } println("Hello,world!") val start = System.currentTimeMillis var res = Produce(arg) val stop = System.currentTimeMillis println(stop-start) /*for(list <- res) { for(el <- list) print(el+" ") println }*/ println(res.length) } def Produce[T](input:Array[Array[T]]):Array[Variant[T]]= { var ret = new Array[Variant[T]](1) for(val forms <- input) { if(forms!=null) { var newRet = new Array[Variant[T]](forms.length*ret.length) if(ret.length>0) { for(val prev <-ret) if(prev!=null) for(val el <-forms) { newRet = newRet:+new Variant[T](el,prev) } } else { for(val el <- forms) { newRet = newRet:+new Variant[T](el,null) } } ret = newRet } } return ret } } class Variant[T](var element:T,prevIoUs:Variant[T]) { }
解决方法
实际上,你最好不要使用for循环. Scala集合库的优势之一是您可以随意使用各种强大的操作.在这种情况下,您希望从表单中获取每个项目并将其转换为Variant.这就是地图的作用.
此外,您的Scala代码似乎没有实际工作.
如果您想要每个成员的所有可能的变体,您真的想要使用递归.这个实现做你想要的:
object test { def produce[T](input: Array[Array[T]],index: Int = 0): Array[List[T]] = { if (index >= input.length) Array() else if (index == input.length-1) input(index).map(elem => List(elem)) else { produce(input,index+1).flatMap(variant => { input(index).map(elem => elem :: variant) }) } } def main() { val arg = Array.tabulate(5,3)((i,j) => i*3+j) println("Hello,world!") val start = System.nanoTime var res = produce(arg) val stop = System.nanoTime println("Time elapsed (ms): " + (stop-start)/1000000L) println("Result length: " + res.length) println(res.deep) } }
让我们解开一点.首先,我们用单个制表指令替换了初始变体的整个构造.制表采用目标大小(此处为5×3),然后是从索引到该矩形的映射到最终值的函数.
我们还制作了一个递归函数. (通常我们会将它设为尾递归,但是让我们现在保持简单.)如何生成所有变体?好吧,所有变体都很明显(在这个位置上的所有可能性)(所有变体来自后面的位置).所以我们递归写下来.
请注意,如果我们像这样递归地构建变体,变体的所有尾部都会相同,这使得List成为一个完美的数据结构:它是一个单链接的不可变列表,所以不必一遍又一遍地复制所有这些尾部,我们只是指向他们.
现在,我们如何实际进行递归?好吧,如果根本没有数据,我们最好返回一个空数组(即索引是否超过数组的末尾).如果我们在变量数组的最后一个元素上,我们基本上希望每个元素都变成长度为1的列表,所以我们使用map来做到这一点(elem => List(elem)).最后,如果我们不在最后,我们从其余部分得到结果(生成(输入,索引1))并使用每个元素制作变体.
让我们首先考虑内部循环:输入(索引).map(elem => elem :: variant).这将从位置索引中的变体中获取每个元素,并将它们粘贴到现有变体上.所以这将给我们一批新的变种.很公平,但我们从哪里获得新变种?我们从列表的其余部分生成它:产生(输入,索引1),然后唯一的技巧是我们需要使用flatMap – 这需要每个元素,从中生成一个集合,并将所有这些集合粘合在一起.
我鼓励你把printlns放在不同的地方看看发生了什么.
最后,请注意,根据您的测试大小,它实际上是一项非常重要的工作量;你无法准确地测量它,即使你像我一样切换到使用更准确的System.nanoTime.在它变得重要之前你需要像表格(12,3)这样的东西(产生500,000个变种).