#arrays #scala #functional-programming #pattern-matching
#массивы #scala #функциональное программирование #сопоставление шаблонов
Вопрос:
я новый программист Scala, и у меня есть вопрос о сопоставлении шаблонов массива Scala:
def countErased(sorted: Array[Array[Int]], acc: Int): Int = {
sorted match{
case Array() | Array(_) => acc
case Array(h,n,_*) =>
if(n(0) < h(1)){
countErased(Array(h,_*), acc 1)
}else{
countErased(Array(n,_*), acc)
}
}
}
По сути, я хочу сделать следующее: когда у нас есть массив длиной больше 2, если n(0)<h (1), вызовите функцию рекурсивно с новым массивом head и любым другим в качестве хвоста. в противном случае вызовите функцию с новым массивом следующего и любого другого в качестве хвоста.
Но этот код выдает мне ошибку:
"error: missing parameter type for expanded function ((<x$1: error>) => x$1.$times) (in solution.scala)
countErased(Array(h,_*), acc 1)"
Что не так?
Комментарии:
1. Это прекрасный пример ситуации, когда вы должны использовать список вместо массива, сопоставление шаблонов имеет несколько ограничений, вызванных определенными деталями реализации и способом настройки иерархии типов (и, конечно, также стиранием). Можно сделать эту работу, используя псевдоним и приведение типов, но это будет просто очень некрасиво.
2. В дополнение к @sinanspd этот код также довольно эффективен, поскольку массивы медленно выполняют все эти операции, вместо этого используйте список . Это было бы проще, красивее, эффективнее и безопаснее.
Ответ №1:
Ваша непосредственная проблема решается в другом ответе: вам просто нужно дать имя splat, например rest@_*
, и использовать это для ссылки на него.
Я просто хочу поддержать совет из комментариев и упомянуть, что вы должны использовать List
, а не массив (у вас может быть функция-оболочка, которая вызывается countErased(array.toList, 0)
, если это удобно).
match
In scala также выглядит намного приятнее и идиоматичнее со списками:
def countErased(sorted: List[Array[Int]], acc: Int) = sorted match {
case h@Array(_, x, _*) :: Array(y, _*) :: tail if y < x => countErased(h :: tail, acc 1)
case _ :: n :: tail => countErased(n :: tail, acc)
case _ => acc
}
В качестве дополнительного замечания, одно отличие от вашей первоначальной реализации заключается в том, что эта реализация не выдает, если в одном из массивов меньше двух элементов.
Ответ №2:
Добро пожаловать в сообщество Scala 🙂
Я согласен с другими комментариями Seq
и List
, как правило, рекомендую, поскольку они неизменяемы (гораздо предпочтительнее, особенно в рекурсивной настройке) и эффективны.
Это выполнимо, Array
хотя ваш код почти работает, все, что мне нужно было добавить, это дать имя для _*
захвата (это то, что rest@
он делает), который затем является экземпляром Seq[Array]
, т.Е. Я мог бы повторно использовать его в рекурсивном вызове:
def countErased(sorted: Array[Array[Int]], acc: Int): Int = {
sorted match {
case Array() | Array(_) => acc
case Array(h, n, rest@_*) =>
if (n(0) < h(1)) {
countErased(h : rest.toArray, acc 1)
} else {
countErased(n : rest.toArray, acc)
}
}
}
Ответ №3:
На самом деле вы довольно близки. Вам просто нужно помнить, что sorted
переменная все еще доступна для вас и содержит то, что вам нужно для построения следующей Array
.
def countErased(sorted: Array[Array[Int]], acc: Int): Int =
sorted match {
case Array() | Array(_) => acc
case Array(h, n, _*) =>
if (n(0) < h(1)) countErased(h : sorted.drop(2), acc 1)
else countErased( sorted.tail, acc)
}
Как уже упоминалось, манипулировать массивами таким образом довольно неэффективно, но если вы застряли, Array[Array[Int]]
это сработает.