我是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
}
但它会逐对对元组进行排序,而不是采用最大的元组(年龄)并将其与下一个元组进行比较。
我做错了什么?
答案 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
这是原始列表,但3
和4
交换位置,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)
相反,我们可以将输家推送到排序部分:
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)
略有改善,但它只将最大数字推到了最后,并换了(33,24)。
整个想法看起来并不乐观。 :)
相反,您可以将最小值从列表中拉出来,然后反复进行。这是伪代码:
def classeur (ages: List[Int]) : List[Int] = {
val min = ages.minimum
val rest = ages.without (minimum)
min :: classeur (rest)
}