Scala концепций функционального программирования вместо нескольких циклов for - PullRequest
0 голосов
/ 04 февраля 2020

Я пытаюсь научиться функциональному программированию на Scala. Прямо сейчас я использую OOP способ создания циклов для работы. У меня есть два списка userCurrentRole и entitlements, над которыми я делаю двойной для l oop:

for {
    curr <- userCurrentRole {
    ent <- entitlements
} {
        if (ent.userEmail.split("@")(0) == curr.head) {
            if (ent.roleName != curr(1)) {
                grantOrRevoke += 1
                grantList += SomeCaseClass(curr.head, ent.roleName)
            }
        }
    }
}

Возможно ли преобразовать этот двойной для l oop в лог c, который использует map или filter или оба, или любые функциональные функции программирования scala, но без for l oop?

РЕДАКТИРОВАТЬ 1: добавлено добавление в список внутри двойного если ..

Ответы [ 3 ]

3 голосов
/ 04 февраля 2020

Хорошая новость: вы уже используете функциональный стиль! Так как for - это не просто oop как таковой, а «для понимания», который десагарсирует в flatMap и map вызовы. Это только легче читать / писать.

Однако, чего вам следует избегать, так это изменчивых переменных, таких как grantOrRevoke, что у вас там есть.

val revocations = for {
    curr <- userCurrentRole {
    ent <- entitlements
    if ent.userEmail.split("@")(0) == curr.head
    if ent.roleName != curr(1)
} yield {
  1
}

revocations.size // same as revocations.sum

Обратите внимание, что if s внутри блока for (обычно) desugar для вызовов withFilter, который часто предпочтительнее вызовов filter, так как последний создает новую коллекцию, тогда как первый избегает этого.

2 голосов
/ 04 февраля 2020

Что ж, вы уже используете некоторые функции более высокого порядка, но вы этого не замечаете, потому что вы верите, что они предназначены для циклов, но не являются циклами. Это просто сахарный синтаксис для вызовов на map & flatMap. Но в вашем случае, также к foreach и тому плюс изменчивость, желание не делает его функциональным.

Я бы порекомендовал вам взглянуть на scalado c , вы обнаружите, что коллекции имеют много полезных методов. Например, в этом случае мы можем использовать count & sum.

val grantOrRevoke = userCurrentRole.iterator.map {
  // Maybe it would be better to have a list of tuples instead of a list of lists.
  case List(username, userRole) =>
    entitlements.count { ent =>
      (ent.userEmail.split("@", 2)(0) == username) && (ent.roleName == userRole)
    }
}.sum
2 голосов
/ 04 февраля 2020

Вы можете написать это так:

val grantOrRevoke = userCurrentRole
    .map(curr => entitlements
        .filter(ent => ent.userEmail.split("@")(0) == curr.head && ent.roleName != curr(1))
        .size)
    .sum
...