How to find the largest element in a list of integers recursively?

前端 未结 16 1606
不知归路
不知归路 2021-01-31 19:49

I\'m trying to write a function which will recursively find the largest element in a list of integers. I know how to do this in Java, but can\'t understand how to do this at Sca

相关标签:
16条回答
  • 2021-01-31 20:30

    If you are required to write a recursive max function on a list using isEmpty, head and tail and throw exception for empty list:

    def max(xs: List[Int]): Int =
      if (xs.isEmpty) throw new NoSuchElementException("max of empty list")
      else if (xs.tail.isEmpty) xs.head
      else if (xs.head > xs.tail.head) max(xs.head :: xs.tail.tail)
      else max(xs.tail)
    

    if you were to use max function on list it is simply (you don't need to write your own recursive function):

    val maxInt = List(1, 2, 3, 4).max
    
    0 讨论(0)
  • 2021-01-31 20:30

    With tail-recursion

      @tailrec
      def findMax(x: List[Int]):Int =  x match {
        case a :: Nil => a
        case a :: b :: c =>  findMax( (if (a > b) a else b) ::c)
      }
    
    0 讨论(0)
  • 2021-01-31 20:32

    I presume this is for the progfun-example

    This is the simplest recursive solution I could come up with

      def max(xs: List[Int]): Int = {
        if (xs.isEmpty) throw new NoSuchElementException("The list is empty")
        val tail = xs.tail
        if (!tail.isEmpty) maxOfTwo(xs.head, max(xs.tail))
        else xs.head
      }
    
      def maxOfTwo(x: Int, y: Int): Int = {
        if (x >= y) x
        else y
      }
    
    0 讨论(0)
  • 2021-01-31 20:33

    Looks like you're just starting out with scala so I try to give you the simplest answer to your answer, how do it recursively:

     def max(xs: List[Int]): Int = {
       def maxrec(currentMax : Int, l: List[Int]): Int = l match {
         case Nil => currentMax
         case head::tail => maxrec(head.max(currentMax), tail) //get max of head and curretn max
       }
       maxrec(xs.head, xs)
     }
    

    This method defines an own inner method (maxrec) to take care of the recursiveness. It will fail ( exception) it you give it an empty list ( there's no maximum on an empty List)

    0 讨论(0)
  • 2021-01-31 20:34

    list.sortWith(_ > ).head & list.sortWith( > _).reverse.head for greatest and smallest number

    0 讨论(0)
  • 2021-01-31 20:35

    This is the most minimal recursive implementation of max I've ever been able to think up:

    def max(xs: List[Int]): Option[Int] = xs match {
      case Nil => None
      case List(x: Int) => Some(x)
      case x :: y :: rest => max( (if (x > y) x else y) :: rest )
    } 
    

    It works by comparing the first two elements on the list, discarding the smaller (or the first, if both are equal) and then calling itself on the remaining list. Eventually, this will reduce the list to one element which must be the largest.

    I return an Option to deal with the case of being given an empty list without throwing an exception - which forces the calling code to recognise the possibility and deal with it (up to the caller if they want to throw an exception).

    If you want it to be more generic, it should be written like this:

    def max[A <% Ordered[A]](xs: List[A]): Option[A] = xs match {
      case Nil => None
      case x :: Nil => Some(x)
      case x :: y :: rest => max( (if (x > y) x else y) :: rest )
    }
    

    Which will work with any type which either extends the Ordered trait or for which there is an implicit conversion from A to Ordered[A] in scope. So by default it works for Int, BigInt, Char, String and so on, because scala.Predef defines conversions for them.

    We can become yet more generic like this:

    def max[A <% Ordered[A]](xs: Seq[A]): Option[A] = xs match {
      case s if s.isEmpty || !s.hasDefiniteSize => None
      case s if s.size == 1 => Some(s(0))
      case s if s(0) <= s(1) => max(s drop 1)
      case s => max((s drop 1).updated(0, s(0)))
    }
    

    Which will work not just with lists but vectors and any other collection which extends the Seq trait. Note that I had to add a check to see if the sequence actually has a definite size - it might be an infinite stream, so we back away if that might be the case. If you are sure your stream will have a definite size, you can always force it before calling this function - it's going to work through the whole stream anyway. See notes at the end for why I really would not want to return None for an indefinite stream, though. I'm doing it here purely for simplicity.

    But this doesn't work for sets and maps. What to do? The next common supertype is Iterable, but that doesn't support updated or anything equivalent. Anything we construct might be very poorly performing for the actual type. So my clean no-helper-function recursion breaks down. We could change to using a helper function but there are plenty of examples in the other answers and I'm going to stick with a one-simple-function approach. So at this point, we can to switch to reduceLeft (and while we are at it, let's go for `Traversable' and cater for all collections):

    def max[A <% Ordered[A]](xs: Traversable[A]): Option[A] = {
      if (xs.hasDefiniteSize) 
        xs reduceLeftOption({(b, a) => if (a >= b) a else b}) 
      else None
    }
    

    but if you don't consider reduceLeft recursive, we can do this:

    def max[A <% Ordered[A]](xs: Traversable[A]): Option[A] = xs match {
      case i if i.isEmpty => None
      case i if i.size == 1 => Some(i.head)
      case i if (i collect { case x if x > i.head => x }).isEmpty => Some(i.head)
      case _ => max(xs collect { case x if x > xs.head => x })
    }
    

    It uses the collect combinator to avoid some clumsy method of bodging a new Iterator out of xs.head and xs drop 2.

    Either of these will work safely with almost any collection of anything which has an order. Examples:

    scala>  max(Map(1 -> "two", 3 -> "Nine", 8 -> "carrot"))
    res1: Option[(Int, String)] = Some((8,carrot))
    
    scala> max("Supercalifragilisticexpialidocious")
    res2: Option[Char] = Some(x)
    

    I don't usually give these others as examples, because it requires more expert knowledge of Scala.

    Also, do remember that the basic Traversable trait provides a max method, so this is all just for practice ;)

    Note: I hope that all my examples show how careful choice of the sequence of your case expressions can make each individual case expression as simple as possible.

    More Important Note: Oh, also, while I am intensely comfortable returning None for an input of Nil, in practice I'd be strongly inclined to throw an exception for hasDefiniteSize == false. Firstly, a finite stream could have a definite or non-definite size dependent purely on the sequence of evaluation and this function would effectively randomly return Option in those cases - which could take a long time to track down. Secondly, I would want people to be able to differentiate between having passed Nil and having passed truly risk input (that is, an infinite stream). I only returned Option in these demonstrations to keep the code as simple as possible.

    0 讨论(0)
提交回复
热议问题