我是Scala
的新手,并试图了解如何处理元组列表,因此我创建了一个虚构的人员列表:
val fichier : List[(String, Int)] = List(("Emma Jacobs",21), ("Mabelle Bradley",53), ("Mable Burton",47), ("Ronnie Walton",41), ("Bill Morton",36), ("Georgia Bates",30), ("Jesse Caldwell",46), ("Jeffery Wolfe",50), ("Roy Norris",18), ("Ella Gonzalez",48))
我想根据某个条件将此列表分成两个列表(无论是partition
和filter
等专用方法)(例如,即使是一边的年龄,也可以是奇数的一些另一方面)并将这两个列表放在另一个。像List[evenList, oddList]
使用Python编写代码非常简单,但显然不适用于Scala:
Python code:
def separate(list):
evenList = [] ; oddList = []
for (i, j) in list:
if j%2==0:
evenList.append((i,j))
else:
oddList.append((i,j))
bothLists = [evenList, oddList]
return bothLists
结果(为便于阅读而改动):
[
[('Bill Morton', 36), ('Georgia Bates', 30), ('Jesse Caldwell', 46), ('Jeffery Wolfe', 50), ('Roy Norris', 18), ('Ella Gonzalez', 48)],
[('Emma Jacobs', 21), ('Mabelle Bradley', 53), ('Mable Burton', 47), ('Ronnie Walton', 41)]
]
我也用这种方式编码,以显示两个短列表如何从迭代演变为另一个:
Python code:
def separate(list):
evenList = [] ; oddList = []
for (i, j) in list:
if j%2==0:
evenList.append((i,j))
yield evenList
else:
oddList.append((i,j))
yield oddList
结果:
[('Emma Jacobs', 21)]
[('Emma Jacobs', 21), ('Mabelle Bradley', 53)]
[('Emma Jacobs', 21), ('Mabelle Bradley', 53), ('Mable Burton', 47)]
[('Emma Jacobs', 21), ('Mabelle Bradley', 53), ('Mable Burton', 47), ('Ronnie Walton', 41)]
[('Bill Morton', 36)]
[('Bill Morton', 36), ('Georgia Bates', 30)]
[('Bill Morton', 36), ('Georgia Bates', 30), ('Jesse Caldwell', 46)]
[('Bill Morton', 36), ('Georgia Bates', 30), ('Jesse Caldwell', 46), ('Jeffery Wolfe', 50)]
[('Bill Morton', 36), ('Georgia Bates', 30), ('Jesse Caldwell', 46), ('Jeffery Wolfe', 50), ('Roy Norris', 18)]
[('Bill Morton', 36), ('Georgia Bates', 30), ('Jesse Caldwell', 46), ('Jeffery Wolfe', 50), ('Roy Norris', 18), ('Ella Gonzalez', 48)]
在下面找到我在Scala中编码的内容:
Scala code:
def separate(list: List[(String, Int)]): List[List[(String, Int)]] = {
val evenList = List[(String, Int)]()
val oddList = List[(String, Int)]()
for ( (i, j) <- list if j%2==0 ) (i,j)::evenList
for ( (i, j) <- list if j%2!=0 ) (i,j)::oddList
val evenAndodd = List(evenList,oddList)
evenAndodd
}
结果:
scala> separate(fichier)
res16: List[List[(String, Int)]] = List(List(), List())
evenList
和oddList
为空。
我想我失败了,但我不会用英语知道这个词。这是关于&#34;可达性&#34; Scala中的变量。
欢迎任何帮助
答案 0 :(得分:2)
您忘记从for表达式中获取值:
def separate(list: List[(String, Int)]): List[List[(String, Int)]] = {
val evenList = for ((i, j) <- list if j % 2 == 0) yield (i, j)
val oddList = for ((i, j) <- list if j % 2 != 0) yield (i, j)
val evenAndOdd = List(evenList, oddList)
evenAndOdd
}
Scala中有两种类型的表达式:
对于没有yield
的表达式, for loop 会返回Unit
:
val x = for ((i, j) <- fichier if j % 2 == 0) (i, j)
x.getClass // Class[Unit] = void
将此视为具有副作用的常规Python循环:
items = []
for item in [1, 2, 3]:
items.append(item + 1)
当你从for
屈服时,你正在使用进行理解,这会产生一个新的集合:
val y = for ((i, j) <- fichier if j % 2 == 0) yield (i, j)
y.take(2) // List(("Bill Morton", 36), ("Georgia Bates", 30))
这更像是Python的理解结果,你可以将其分配给变量:
items = [item + 1 for item in [1, 2, 3]]
答案 1 :(得分:1)
首先,请注意partition
上已有方法List
:
val fichier : List[(String, Int)] = List(
("Emma Jacobs",21), ("Mabelle Bradley",53),
("Mable Burton",47), ("Ronnie Walton",41),
("Bill Morton",36), ("Georgia Bates",30),
("Jesse Caldwell",46), ("Jeffery Wolfe",50),
("Roy Norris",18), ("Ella Gonzalez",48)
)
val (odd, even) = fichier.partition(_._2 % 2 == 1)
println(odd)
println(even)
打印:
List((Emma Jacobs,21), (Mabelle Bradley,53), (Mable Burton,47), (Ronnie Walton,41))
List((Bill Morton,36), (Georgia Bates,30), (Jesse Caldwell,46), (Jeffery Wolfe,50), (Roy Norris,18), (Ella Gonzalez,48))
您当然可以自行轻松实现,如下所示:
def separate[A](list: List[A])(predicate: A => Boolean): (List[A], List[A]) = {
import scala.collection.mutable.ListBuffer
val trueListBuf = new ListBuffer[A]
val falseListBuf = new ListBuffer[A]
for (x <- list) {
if (predicate(x)) trueListBuf += x
else falseListBuf += x
}
(trueListBuf.toList, falseListBuf.toList)
}
val (odd2, even2) = separate(fichier){ case (n, a) => a % 2 == 1 }
println(odd2)
println(even2)
这会输出与之前相同的结果。
这里要注意几点:
ListBuffer
来提高效率,因为它附加了一个可变的
ListBuffer
在不变的时间内工作,而对不可变的工作则相同
List
有点麻烦separate
实施A
方法
在列表中。而不是硬编码% 2
- 检查方法,我们通过
来自外部的通用predicate
predicate
位于第二个(单独的)参数列表中。
这使我们能够使用更好的(至少在我看来)语法
separate(list){ predicateImpl }
。这也简化了类型推断
对于predicate
参数。case (name, age) => ...
谓词。答案 2 :(得分:0)
您可以使用模式匹配,递归和内部函数来解决它:
def separate (list: List[(String, Int)]): List[List[(String, Int)]] = {
def separate (list: List[(String, Int)], first: List[(String, Int)], second: List[(String, Int)]):
List[List[(String, Int)]] = list match {
case Nil => List (first, second)
case ((s, i)) :: ps => if (i % 2 !=0)
separate (ps, (s, i) :: first, second) else
separate (ps, first, (s, i) :: second)
}
separate (list, List[(String, Int)](), List[(String, Int)]())
}
外部函数只设置2个空列表,奇数和偶数,传递它们,随便将下一个元素添加到其中一个。
在对类型进行推广时,它会变得更好。我们摆脱了所有那些(String,Int)元组并为每个Type提供解决方案,我们只需要将函数从A传递给Boolean:
def separate [A] (list: List[A]) (f: A => Boolean): List[List[A]] = {
def separate (list: List[A], first: List[A], second: List[A]): List[List[A]] = list match {
case Nil => List (first, second)
case p :: ps => if (f (p))
separate (ps, p :: first, second) else
separate (ps, first, p :: second)
}
separate (list, List[A](), List[A]())
}
def evan (si : (String, Int)) : Boolean = (si._2 % 2) == 0
separate (fichier) (evan)
或
separate (fichier) (_._2 % 2 == 0)