简体   繁体   中英

Scala functional programming concepts instead of multiple for loops

I am trying to learn functional programming in Scala. Right now I'm using the OOP way of having for loops to do a job. I have two lists userCurrentRole and entitlements over which I'm doing a double for loop:

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?

EDIT 1: Added a list addition inside the 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. It's only easier to read / write.

However, the thing you should avoid is mutable variables, like the grantOrRevoke thing you have there.

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.

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. They are just sugar syntax for calls to map & flatMap . But in your case, also to foreach and that plus mutability, is want doesn't make it functional.

I would recommend you to take a look to the scaladoc , you will find that collections have a lot of useful methods. For example, in this case, we may use 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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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