该算法从序列的每个成员的变体创建序列的所有可能变体.
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])
{
}
解决方法:
正如其他人所说,不同之处在于你如何使用这些系列. Scala中的数组与Java的原始数组[]相同,它与C#的原始数组[]相同. Scala非常聪明,能够按照您的要求进行操作(即,在最后使用新元素复制整个数组),但不是那么聪明,以至于告诉您最好使用不同的集合.例如,如果您只是将Array更改为ArrayBuffer,它应该更快(与C#相当).
实际上,你最好不要使用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个变种).
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。