处理Scala中的元组列表 - 第4部分

时间:2018-02-19 16:06:39

标签: scala list tuples

我是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))

我想根据某个条件将此列表分成两个列表(无论是partitionfilter等专用方法)(例如,即使是一边的年龄,也可以是奇数的一些另一方面)并将这两个列表放在另一个。像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())

在evenAndodd列表中,

evenListoddList为空。

我想我失败了,但我不会用英语知道这个词。这是关于&#34;可达性&#34; Scala中的变量。

欢迎任何帮助

3 个答案:

答案 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中有两种类型的表达式:

  1. For loop
  2. 为了理解
  3. 对于没有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)