简体   繁体   English

Scala 函数式编程概念而不是多个 for 循环

[英]Scala functional programming concepts instead of multiple for loops

I am trying to learn functional programming in Scala.我正在尝试在 Scala 中学习函数式编程。 Right now I'm using the OOP way of having for loops to do a job.现在我正在使用 OOP 方式让 for 循环来完成工作。 I have two lists userCurrentRole and entitlements over which I'm doing a double for loop:我有两个列表userCurrentRoleentitlements我做了双重for循环在其中:

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)
            }
        }
    }
}

Is it possible to convert this double for loop into a logic that uses map or filter or both or any functional programming features of scala, but without a for loop?是否可以将这个双 for 循环转换为使用mapfilter或两者或任何 scala 的函数式编程特性的逻辑,但没有for循环?

EDIT 1: Added a list addition inside the double if..编辑 1:在 double if.. 中添加了一个列表添加

The good news is: you are already using functional style!好消息是:你已经在使用函数式风格了! Since the for is not a loop per se, but a "for comprehension", which desugars into flatMap and map calls.因为for本身不是一个循环,而是一个“for comprehension”,它被分解为flatMapmap调用。 It's only easier to read / write.它只是更容易读/写。

However, the thing you should avoid is mutable variables, like the grantOrRevoke thing you have there.但是,您应该避免的是可变变量,例如您在那里拥有的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

Note that the if s inside the for block (usually) desugar to withFilter calls, which is often preferable to filter calls, since the latter builds up a new collection whereas the former avoids that.请注意, for 块中的if s(通常)对withFilter调用进行脱糖,这通常比filter调用更可取,因为后者建立了一个新集合,而前者避免了这种情况。

You can write it like this:你可以这样写:

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

Well, you are already using some higher order functions, only that you don't notice it, because you believe those are for loops, but they aren't loops.好吧,您已经在使用一些高阶函数,只是您没有注意到它,因为您认为它们是 for 循环,但它们不是循环。 They are just sugar syntax for calls to map & flatMap .它们只是调用mapflatMap语法糖。 But in your case, also to foreach and that plus mutability, is want doesn't make it functional.但是在您的情况下,对于foreach和可变性,想要并不能使其发挥作用。

I would recommend you to take a look to the scaladoc , you will find that collections have a lot of useful methods.我建议你看看scaladoc ,你会发现集合有很多有用的方法。 For example, in this case, we may use count & sum .例如,在这种情况下,我们可以使用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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM