Scala:迭代的优雅解决方案(列表,列表)

时间:2015-05-12 16:12:59

标签: scala

我试图想出一个优雅的"迭代两个列表(值对)的解决方案,并对结果值执行一些测试。

有什么想法吗?这是我目前所拥有的,但我得到的是"值过滤器不是(List [Int],List [Int])的成员,"令我感到惊讶的是我认为这会起作用。而且,我觉得在Scala中必须有更清晰的表达方式。

val accounts = random(count = 100, minimum = 1, maximum = GPDataTypes.integer._2)
val ids = random(count = 100, minimum = 1, maximum = GPDataTypes.integer._2)

for ((id, accountId) <- (ids, accounts)) {
  val g = new GPGlimple(Some(id), Some(timestamp), accountId, false, false, 2)
  println(g)
  g.accountId mustEqual accountId
  g.id mustEqual id
  g.created.get must beLessThan(System.currentTimeMillis)
  g.layers must beNone
  g.version must be equalTo 2
}

2 个答案:

答案 0 :(得分:2)

最简单的解决方案是zip

(ids zip accounts)

zip的文档说:

  

通过成对组合相应的元素,返回从此列表和另一个可迭代集合形成的列表。

换句话说,zip将返回元组列表。

zipped方法也适用于此处:

(ids, accounts).zipped

您可以找到2元组herezipped来源。请注意,这可以通过(T, U)的丰富来实现,其中T可隐式查看为TraversableLike,而U可隐式查看为IterableLike。该方法返回ZippedTraversable2,这是一个封装此类压缩返回的最小接口,通过禁止创建中间集合,可以更有效地处理大型序列。这些通常更具性能,因为它们在内部使用iterators,如源中所示。

请注意,此处的返回值不同,可能会影响下游行为。一个重要的区别是ZippedTraversable2上的正常组合方法与元组Traversable上的方法略有不同。 ZippedTraversable2上的方法通常期望2个参数的函数,而Traversable个元组上的方法将期望具有单个参数的函数是元组。例如,您可以在REPL中检查foreach方法:

val s1 = List(1, 2, 3)
val s2 = List('a', 'b', 'c')

(s1 -> s2).zipped.foreach _
// ((Int, Char) => Any) => Unit = <function1>
(s1 zip s2).foreach _
// (((Int, Char)) => Any) => Unit = <function1> 
//Notice the extra parens here, signifying a method with a tuple argument

这种差异意味着您在使用zipzipped时有时必须使用不同的语法:

(s1 zip s2).map { x => x._1 + x._2 }
(s1, s2).zipped.map { x => x._1 + x._2 } //This won't work!  The method shouldn't expect a tuple argument

//conversely
(s1, s2).zipped.map { (x, y) => x + y }
(s1 zip s2).map { (x, y) => x + y } //This won't work!  The method shouldn't expect 2 arguments

//Added note: methods with 2 arguments can often use the more concise underscore notation:
(s1, s2).zipped.map { _ + _ }

请注意,如果您使用case表示法,则可以采用以下方式覆盖:

//case works for both syntaxes
(s1, s2).zipped.map { case (x, y) => x + y } \
(s1 zip s2).map { case (x, y) => x + y }

这是有效的,因为编译器理解带有两个参数或单个元组参数的方法的这种表示法,如section 8.5 of the spec中所述:

val f: (Int, Int) => Int = { case (a, b) => a + b }
val g: ((Int, Int)) => Int = { case (a, b) => a + b }

答案 1 :(得分:1)

使用zip

for ((id, accountId) <- ids.zip(accounts)) {
   // ...     
}