【问题标题】:Work on list of tuples in Scala - part 2在 Scala 中处理元组列表 - 第 2 部分
【发布时间】:2018-07-25 06:27:03
【问题描述】:

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

  }

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

我做错了什么?

【问题讨论】:

  • 它对我有用。你确定你得到完全相同的列表?
  • 你说的什么都没发生是什么意思?我认为您的算法无法正确排序列表,它只会获取两个元素并重新排序它们,但不会针对整个列表。
  • @KevinHoerr 我编辑了我的主题。它不会返回完全相同的列表,而是将元组两两排序
  • @nicodp 对。有什么建议可以解决这个问题,不管 sortBy 方法是什么?

标签: scala list pattern-matching tuples


【解决方案1】:

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

但是为了玩这个,我们可以在Scala中实现mergesort如下:

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 预定义的排序算法。

【讨论】:

  • 好的,这对我来说有点复杂,所以我会保存你的答案,等我在 Scala 中的水平提高时再看一遍。谢谢
  • 如果您阅读mergesort 的工作原理,您会看到我的代码中描述的算法,这几乎是基本的 Scala,只是几个模式匹配定义和递归调用。
  • 你好。我已经阅读了合并排序算法并试图了解您对列表进行排序并将 cmets 添加到您的代码中。请你看看他们,告诉我我的方法是否正确?
  • @Yuva 刚刚评论了它并附上了解释
【解决方案2】:

返回的结果并不完全相同。如果您将人名更改为从 1 到 10 的数字,您可以看到它返回 1, 2, 4, 3, 6, 5, 7, 8, 9, 10,这是原始列​​表,但 34 交换了位置,56 交换了位置。

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

fichier.sortBy(f =&gt; f._2)

或者更简洁:

fichier.sortBy(_._2)

【讨论】:

  • 我认为这个算法会采用这种方式:`(1 and 2) then (2 and 3), ..., (9 and 10).我知道我可以使用 sortyBy 但想编写自己的函数
  • 不完全是,如果你想这样做,你对classeur 的递归调用将需要包含前一个元素,例如{ (name1, age1) :: classeur((name2, age2) :: t) } 但这仍然不会对任何输入的列表进行排序。
  • 我还认为值得一提的是,对于任何比较排序算法,您可以获得的最佳时间复杂度是O(nlog(n))。换句话说,你不能设计一个比较排序算法来一次对任何列表进行排序。
  • you cannot design a comparison sort algorithm that sorts any list with one pass. 好的。我会牢记这一点。
【解决方案3】:

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

  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) 
  }

【讨论】:

    猜你喜欢
    • 2018-07-29
    • 2018-07-26
    • 2018-07-24
    • 2015-07-06
    • 2014-01-23
    • 1970-01-01
    • 2020-04-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多