Найдите второй последний пункт в списке, пожалуйста, объясните это решение - PullRequest
9 голосов
/ 30 июня 2011
// But pattern matching also makes it easy.
  def penultimateRecursive[A](ls: List[A]): A = ls match {
    case h :: _ :: Nil => h
    case _ :: tail     => penultimateRecursive(tail)
    case _             => throw new NoSuchElementException
  }

Может кто-нибудь прокомментировать, что это делает построчно?

Является ли [A] универсальным, как в c #, мы бы сделали?

ч, похоже, не определено?

Я думаю, что основная часть алгоритма - это рекурсивный вызов:

case _ :: tail     => penultimateRecursive(tail)

Кажется, что 'нет проверки на 2 предмета в списке, а затем брать 1-й предмет, чтобы получить 2-й последний, в замешательстве!

Ответы [ 4 ]

10 голосов
/ 30 июня 2011

Ключи к пониманию сопоставления с образцом состоят в том, чтобы понять, что x :: y будет только совпадать со списком с одним элементом x, за которым следует остальная часть списка y (который может быть простоNil, или может быть много элементов), и это _ означает "здесь должно быть что-то, но мы не будем называть это именем".(И что совпадения происходят по порядку, и что списки заканчиваются на Nil.)

Вы правы, что [A] является универсальным типом.

Итак, первая строка:

case h :: _ :: Nil => h

говорит, что если наш список выглядит (концептуально) Node(h) -> Node(whatever) -> Nil, то мы возвращаем h.Это ровно двухэлементный список с выбранным первым элементом.Обратите внимание, что Nil не не соответствует произвольному хвосту списка;он соответствует только элементу конца списка Nil.Это происходит из-за правила, которое Scala использует для различения двух: переменные нижнего регистра обрабатываются как символы подстановки, которым необходимо заполнить соответствующее значение, а переменные верхнего регистра обрабатываются как константы для сопоставления.(Если вам нужно сопоставить имя в нижнем регистре, вы можете, если окружите его обратными чертами.)

Хорошо, теперь предположим, что это не список из двух элементов.Тогда, если он не пустой, он будет соответствовать

case _ :: tail => penultimateRecursive(tail)

, поэтому, если у нас нет двухэлементного списка, мы выбрасываем первый элемент и пытаемся снова.Наконец, если мы каким-то образом никогда не заканчивали двухэлементным списком, мы получаем

case _ => throw new NoSuchElementException

и все готово.(На самом деле это также может быть case Nil, поскольку это единственная возможность, которая не соответствует двум другим записям.)

4 голосов
/ 30 июня 2011

A является переменной типа, что означает, что функция определена для любого типа A.

h связана с сопоставлением с шаблоном: первые case состояния, если естьровно два элемента, затем вызвать первый h и вернуть его.

Кажется, 'нет проверки для 2 элементов в списке

Существует:h :: _ :: Nil означает «элемент h, за которым следует любой элемент, после которого больше нет элементов».Nil не элемент, это конец списка.

и затем взятие 1-го предмета, чтобы получить 2-й последний

Взятие первого из двухэлементного списка означает взятие предпоследнего.Если список содержит меньше или больше элементов, чем два, применяются два других случая.

3 голосов
/ 30 июня 2011

larsmans и Rex уже рассмотрели ваши вопросы, но см. Главу 9 для более подробной информации о '::' http://www.scala -lang.org / documents / files / ScalaByExample.pdf

1 голос
/ 30 июня 2011

Первая строка означает, что любой элемент списка h будет возвращен, если за h следует другой элемент и указатель Nil (в конце списка).Фактический элемент, следующий за h, не важен, поэтому вы используете _, чтобы указать, что элемент есть, но вам не важно его значение.

Если первый случай не совпадает, второй случайВызовите рекурсию, если список имеет элемент head и хвост хотя бы одного элемента.

Наконец, вы получаете доступ к спискам, состоящим только из одного элемента.Еще раз, вам не нужно заботиться о фактическом значении значения элементов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...