加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

为什么Scala中的相同算法比C#慢得多?以及如何让它更快?

发布时间:2020-12-16 09:09:17 所属栏目:安全 来源:网络整理
导读:该算法从序列的每个成员的变体创建序列的所有可能变体. C#代码: static void Main(string[] args){ var arg = new ListListint(); int i = 0; for (int j = 0; j 5; j++) { arg.Add(new Listint()); for (int j1 = i; j1 i + 3; j1++) { //if (j1 != 5) arg
该算法从序列的每个成员的变体创建序列的所有可能变体.

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个变种).

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读