как выполнить сопоставление шаблонов scala в массиве?

#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]] это сработает.