2016-11-04 5 views
1

Я новый для Scala. В качестве упражнения я пытаюсь написать заявление соответствия над списком кортежей с охранниками. Я знаю, что карта решит проблему, но я пытаюсь понять, как сочетать шаблоны.Scala matching Список кортежей с охраной

Я пытаюсь написать функцию, которая принимает аргумент List[(Char, Int)]. Функция сортирует записи, и если две записи имеют одинаковое значение ключа, они складываются вместе. Таким образом, следующий аргумент List(('q', 1'), ('a', 1), ('c', 2), ('a', 2), ('c', 1)) стал бы List(('a', 3), ('c', 3'), ('q', 1)).

Я пришел со следующим кодом:

def sortAndAggregateList(chars: List[(Char, Int)]) : List[(Char, Int)] = { 
    chars match { 
    case (charP1, numP1) :: (charP2, numP2) :: (x : List[(String, Int)]) if (charP1 > charP2) => 
     sortAndAggregateList((charP2, numP2) :: (charP1, numP1) :: x) 
    case (charP1, numP1) :: (charP2, numP2) :: (x : List[(String, Int)]) if (charP1 < charP2) => 
     sortAndAggregateList((charP1, numP1) :: (charP2, numP2) :: x) 
    case (charP1, numP1) :: (charP2, numP2) :: (x : List[(String, Int)]) if (charP1 == charP2) => 
     sortAndAggregateList((charP1, numP1 + numP2) :: x) 
    case Nil => 
     Nil 
    } 
} 

Но я получаю следующее предупреждение:

: 14: предупреждение: бесплодными испытания типа: значение списка типа [(Char, Int)] также не может быть List [(String, Int)] (лежащий в основе List [(String, Int)]) (но все равно может совпадать с его стиранием)

Я попытался удалить список, но если я это сделаю, ошибка x имеет тип Any.

Любые предложения?

+0

Посмотреть сообщение об ошибке: вы сопрягая против 'chars', который является' List [(Char, Int)] ', но в шаблоне вы ожидаете, что' x' будет 'List [(String, Int)]'. – Josef

ответ

2

ошибка - это ваш тип проверки, который вы выполняете после каждого оператора case (: List [(String, Int)]).

Если вы измените свой код на следующие ошибки исчезает:

def sortAndAggregateList(chars: List[(Char, Int)]) : List[(Char, Int)] = { 
    chars match { 
    case (charP1, numP1) :: (charP2, numP2) :: x if (charP1 > charP2) => 
     sortList(p1 :: p2 :: x) 
    case (charP1, numP1) :: (charP2, numP2) :: x if (charP1 < charP2) => 
     sortList(p2 :: p1 :: x) 
    case (charP1, numP1) :: (charP2, numP2) :: x if (charP1 == charP2) => 
     val p3: (Char, Int) = (charP1, numP1 + numP2) 
     sortList(p3 :: x) 
    case x => 
     x 
    case Nil => 
     Nil 
    } 
} 

После этого вы увидите, что компилятор говорит вам, что p1 и p2 не определены. Чтобы исправить это, вам нужно установить их как p1 = (charP1, numP1) и p2 = (charP2, numP2). Чтобы решить эту проблему с помощью синтаксиса вы можете сделать следующее:

def sortAndAggregateList(chars: List[(Char, Int)]) : List[(Char, Int)] = { 
    chars match { 
    case (charP1, numP1) :: (charP2, numP2) :: x if (charP1 > charP2) => 
     sortList((charP1, numP1) :: (charP2, numP2) :: x) 
    case (charP1, numP1) :: (charP2, numP2) :: x if (charP1 < charP2) => 
     sortList((charP2, numP2) :: (charP1, numP1) :: x) 
    case (charP1, numP1) :: (charP2, numP2) :: x if (charP1 == charP2) => 
     val p3: (Char, Int) = (charP1, numP1 + numP2) 
     sortList(p3 :: x) 
    case x => 
     x 
    case Nil => 
     Nil 
    } 
} 

Теперь единственным недостающим звеном является функция, которая список сортировки вы не добавили. Я не уверен, если это будет работать, потому что я думаю, что дело:

case x => x 

должно быть:

case x :: Nil => x :: Nil 

В противном случае х будет соответствовать что-нибудь.Который также оставляет вам возможность извлечь случай:

case Nil => Nil 

, если вы не хотите, чтобы удалить случай х => х

+0

этот 'case x => x' будет работать – pamu

+0

да вы правы , поэтому я добавил, что он соответствует чему угодно, даже Нилу. – biro

+0

case Nil => Nil является избыточным – pamu

0

Аннотации дополнительного типа после х не являются необходимыми и неправильными.

удалить это

(x : List[(String, Int)]) 

вместо этого использовать (не обязательно. Вы можете опустить аннотацию типа)

(x : List[(Char, Int)]) 

Полная функция

def sortAndAggregateList(chars: List[(Char, Int)]): List[(Char, Int)] = chars match { 
    case (charP1, numP1) :: (charP2, numP2) :: x if charP1 > charP2 => 

     sortAndAggregateList((charP2, numP2) :: (charP1, numP1) :: x) 

    case (charP1, numP1) :: (charP2, numP2) :: x if charP1 < charP2 => 

     sortAndAggregateList((charP1, numP1) :: (charP2, numP2) :: x) 

    case (charP1, numP1) :: (charP2, numP2) :: x if charP1 == charP2 => 

     sortAndAggregateList((charP1, numP1 + numP2) :: x) 

    case x => x 
    } 

код будет гораздо чище, если вы рассматриваете свертывание кортежей

def sortAndAggregateList(chars: List[(Char, Int)]): List[(Char, Int)] = chars match { 
    case a :: b :: x if a._1 > b._2 => 

     sortAndAggregateList(b :: a :: x) 

    case a :: b :: x if a._1 < b._1 => 

     sortAndAggregateList(a :: b :: x) 

    case a :: b :: x if a._1 == b._1 => 

     sortAndAggregateList((a._1, (a._2 + b._2)) :: x) 

    case x => x 

    } 

кейс case x => x будет соответствовать как списку дел Nil, так и списку, имеющим один элемент.

+0

Эта функция имеет одну слабость. Он не будет работать со списком, содержащим только одну запись, например: List ((«t», 1)) – biro

+0

@biro спасибо за предложение исправлено – pamu

Смежные вопросы