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

时间:2018-02-14 15:57:25

标签: scala list pattern-matching 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))

我希望自我编码一个按年龄排序上升的功能:

  def classeur(personne: List[(String, Int)]) : List[(String, Int)] = 
  personne match {

    case (name1, age1) :: (name2, age2) :: t if age1 <= age2 => { (name1, age1) :: (name2, age2) :: classeur (t ) }
    case (name1, age1) :: (name2, age2) :: t if age2 < age1 => { (name2, age2) :: (name1, age1) :: classeur (t ) }
    case x => x

  }

但它会逐对对元组进行排序,而不是采用最大的元组(年龄)并将其与下一个元组进行比较。

我做错了什么?

3 个答案:

答案 0 :(得分:2)

如果您想自己编写排序算法,我建议您阅读Sorting algorithm中的不同实现。

但是为了解决这个问题,我们可以在mergesort中实施Scala,如下所示:

def merge(firstHalf: List[(String, Int)], secondHalf: List[(String, Int)]): List[(String, Int)] = firstHalf match {
  case Nil => secondHalf
  case x::xs => secondHalf match {
    case Nil => firstHalf
    case y::ys => if (x._2 < y._2) x::merge(xs, secondHalf) else y::merge(firstHalf, ys)
  } 
}

def classeur(personne: List[(String, Int)]) : List[(String, Int)] = 
  personne match {
    case Nil => Nil
    case List(x) => List(x)
    case _ => {
      val (firstHalf, secondHalf) = personne.splitAt(personne.length / 2)
      merge(classeur(firstHalf), classeur(secondHalf))
    }
  }

你会得到:

scala> classeur(fichier)
res0: List[(String, Int)] = List((Roy Norris,18), (Emma Jacobs,21), (Georgia Bates,30), (Bill Morton,36), (Ronnie Walton,41), (Jesse Caldwell,46), (Mable Burton,47), (Ella Gonzalez,48), (Jeffery Wolfe,50), (Mabelle Bradley,53))

尽管如此,我建议您查看@Tom的答案,因为您应该尽可能使用Scala预定义的排序算法。

答案 1 :(得分:1)

它没有完全相同。如果您将人物的姓名更改为1到10之间的数字,则可以看到它返回1, 2, 4, 3, 6, 5, 7, 8, 9, 10这是原始列​​表,但34交换位置,5 1}}和6交换位置。

这就是你的代码所做的,它遍历列表并查看每对元素,并对它们进行排序。即,如果输入列表按降序排列,则结果为2, 1, 4, 3, 6, 5, 8, 7, 10, 9。 如果要在没有模式匹配的情况下对其进行排序,可以使用sortBy

fichier.sortBy(f => f._2)

或者更简洁:

fichier.sortBy(_._2)

答案 2 :(得分:0)

原则上,我们对整个名称并不感兴趣,可以先尝试用简单的数字对自己进行排序:

  def classeur (ages: List[Int]) : List[Int] = ages match {
      case age1 :: age2 :: t if age1 <= age2 => { age1 :: age2 :: classeur (t)) }
      case age1 :: age2 :: t if age1 > age2 => { age2 :: age1 :: classeur (t)) }
    case x => x
  }

这是同样的问题,只是简单描述。 :)

所以对于年龄列表(11,22,33,24,45,6)

  • 我们比较了11,22并且在确认其余部分之后返回,11,22
  • 我们比较33 24并返回(11,22(24,33(cl(r))
  • 我们比较45 6并返回(11,22,24,33,6 45)

相反,我们可以将输家推送到排序部分:

  def classeur (ages: List[Int]) : List[Int] = ages match {
      case age1 :: age2 :: t if age1 <= age2 => { age1 :: classeur (age2 :: t)) }
      case age1 :: age2 :: t if age1 > age2 => { age2 :: classeur (age 1:: t)) }
    case x => x
  }

但这并不能解决整个问题:

我们的年龄列表(11,22,33,24,45,6)

  • 我们比较11,22并返回(11 cl(22 :: r))
  • 我们比较22,33并返回(11 22 cl(33 :: r))
  • 我们比较33,24并返回(11 22 24 cl(33 :: r))
  • 我们比较33,45并返回(11 22 24 33 cl(45 :: r)
  • 我们比较45,6和返回(11 22 24 33 6 45)

略有改善,但它只将最大数字推到了最后,并换了(33,24)。

整个想法看起来并不乐观。 :)

相反,您可以将最小值从列表中拉出来,然后反复进行。这是伪代码:

  def classeur (ages: List[Int]) : List[Int] = {
      val min = ages.minimum
      val rest = ages.without (minimum) 
      min :: classeur (rest) 
  }