Могу ли я сделать это с помощью «yield» в Scala? (Вложенные циклы for, дающие вектор комбинаций)

#scala

#scala

Вопрос:

Отказ от ответственности: я довольно новичок в любом современном виде кодирования. (БАЗОВЫЙ Паскаль еще в средней школе, немного Python несколько лет назад, и теперь я пытаюсь научить себя Scala.)

Предполагается, что этот код генерирует рандомизированную колоду карт с мастями и значениями, которые я настраиваю в первых двух строках. У меня есть код, который работает, используя изменяемые переменные, но я всегда читаю, что лучше избегать изменяемых переменных, поэтому я попытался использовать вместо этого «yield». Это был результат после того, как я изменил код:

 import util.Random.shuffle

val suits = Vector[String]("s", "m", "p")
val values = Vector[Int](1, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 5, 5, 9)

class Card(val suit:String, val value:Int) {}
class Deck() {
    var cardsInDeck:Vector[Card] = Vector()
}

def makeDeck(suits:Vector[String], values:Vector[Int]):Vector[Card] = {
    for (i <- suits) yield {
        for (j <- values) new Card(i, j) 
    }
}

val TheDeck = new Deck
TheDeck.cardsInDeck = util.Random.shuffle(makeDeck(suits, values))
for (i <- TheDeck.cardsInDeck) {
    println(s"${i.suit}${i.value}")
}
  

Это выдает мне сообщение об ошибке, указывающее на стрелку после «i» и говорящее о несоответствии типов.

Есть ли что-нибудь подобное, что будет работать?

Если нет, как вы думаете, я должен просто придерживаться исходной версии изменяемой переменной? (Я предполагаю, что вы можете себе представить, как это было в основном — начните с переменной со значением по умолчанию и добавляйте к ней по одному элементу за раз, выполняя итерации по вложенным циклам.)

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

Заранее благодарю вас…

Ответ №1:

 def makeDeck(suits: Vector[String], values: Vector[Int]): Vector[Card] = {
    for {
      i <- suits
      j <- values
    } yield new Card(i, j) 
}
  

Вы забыли второй yield перед new Card . Однако нет необходимости вкладывать циклы for, вместо этого структурируйте их, как указано выше.

Вам следует подумать cardsInDeck о создании параметра a val и конструктора, поэтому Deck он может быть неизменяемым, как Card есть. Это также было бы удобно для Deck и Card для классов case.

Комментарии:

1. Спасибо. Я еще не совсем понял, в чем преимущество классов case, но я все еще учусь. Что касается того, должна ли колода быть изменяемой или нет, сейчас кажется, что так и должно быть, поскольку она будет расти и уменьшаться по мере продолжения игры. Разве это не следует, хотя?

2. Кстати, мне даже не приходило в голову, что там нужен второй yield, но в любом случае мне нравится ваш способ лучше, легче читать и т.д.

3. Deck может быть изменяемым или неизменяемым. Если вы сделаете его неизменяемым, для каждой операции, которая изменяет колоду, потребуется создать новый объект Deck. Иногда это неудобно для игр и других симуляций.