SCALA:生成满足某些条件的Tuple2对象的列表

时间:2018-07-29 07:37:32

标签: scala

我要生成list的{​​{1}}。列表中的每个元组Tuple2 objects均应满足以下条件:(a,b)a都是完美的平方,b  以及(b/30)<a<ba>Nb>N甚至可以是N)   我正在尝试编写BigInt来生成满足以上要求的scala function吗?    这是我的尝试。.它对于Ints和Longs来说很好。.但是对于BigInt,我面临着sqrt问题。.这是我的编码方法,如下所示:

the List of Tuples

使用BigInt平方根算法对此进行了改进,如下所示:

scala>  def genTups(N:Long) ={
     |  val x = for(s<- 1L to Math.sqrt(N).toLong) yield s*s;
     |  val y = x.combinations(2).map{ case Vector(a,b) => (a,b)}.toList
     |  y.filter(t=> (t._1*30/t._2)>=1)
     | }
genTups: (N: Long)List[(Long, Long)]

scala> genTups(30)
res32: List[(Long, Long)] = List((1,4), (1,9), (1,16), (1,25), (4,9), (4,16), (4,25), (9,16), (9,25), (16,25))

我感谢我在算法上的任何改进。

2 个答案:

答案 0 :(得分:2)

您可以通过将sqrt的计算方式更改为以下方式来避免算法中的x

  val x = (BigInt(1) to N).map(x => x*x).takeWhile(_ <= N)

最后一个函数是:

def genTups(N: BigInt) = {
  val x = (BigInt(1) to N).map(x => x*x).takeWhile(_ <= N)
  val y = x.combinations(2).map { case Vector(a, b) if (a < b) => (a, b) }.toList
  y.filter(t => (t._1 * 30 / t._2) >= 1)
}

您还可以将其重写为如下所示的单个操作链:

def genTups(N: BigInt) =
  (BigInt(1) to N)
    .map(x => x * x)
    .takeWhile(_ <= N)
    .combinations(2)
    .map { case Vector(a, b) if a < b => (a, b) }
    .filter(t => (t._1 * 30 / t._2) >= 1)
    .toList

为了追求性能,我想出了这个递归版本,该版本似乎要快得多

def genTups(N1: BigInt, N2: BigInt) = {
  def sqt(n: BigInt): BigInt = {
    var a = BigInt(1)
    var b = (n >> 5) + BigInt(8)
    while ((b - a) >= 0) {
      var mid: BigInt = (a + b) >> 1
      if (mid * mid - n > 0) {
        b = mid - 1
      } else {
        a = mid + 1
      }
    }
    a - 1
  }

  @tailrec
  def loop(a: BigInt, rem: List[BigInt], res: List[(BigInt, BigInt)]): List[(BigInt, BigInt)] =
    rem match {
      case Nil => res
      case head :: tail =>
        val a30 = a * 30
        val thisRes = rem.takeWhile(_ <= a30).map(b => (a, b))

        loop(head, tail, thisRes.reverse ::: res)
    }

  val squares = (sqt(N1) to sqt(N2)).map(s => s * s).toList

  loop(squares.head, squares.tail, Nil).reverse
}

循环的每次递归都会为给定值a添加所有匹配对。结果是反向生成的,因为添加到长列表的前面比添加到列表的末尾要快得多。

答案 1 :(得分:-1)

首先创建一个函数来检查数字是否为完美正方形。

def squareRootOfPerfectSquare(a: Int): Option[Int] = {
  val sqrt = math.sqrt(a)
  if (sqrt % 1 == 0)
    Some(sqrt.toInt)
  else
    None
}

然后,创建另一个函数,该函数将根据上述条件计算此元组列表。

def generateTuples(n1:Int,n2:Int)={
  for{
    b <- 1 to n2;
    a <- 1 to n1 if(b>a && squareRootOfPerfectSquare(b).isDefined && squareRootOfPerfectSquare(a).isDefined)
  } yield ( (a,b) )
}

然后在使用参数generateTuples(5,10) 调用函数时,您将获得输出

res0: scala.collection.immutable.IndexedSeq[(Int, Int)] = Vector((1,4), (1,9), (4,9))

希望有帮助!