Converting Imperative Expressions to Functional style paradigm - scala

I have the following Scala snippet from my code. I am not able to convert it into functional style. I could do it at other places in my code but not able to change the below one to functional. Issue is once the code exhausts all pattern matching options, then only it should send back "NA". Following code is doing that, but it's not in functional style (for-yield)
var matches = new ListBuffer[List[String]]()
for (line <- caselist){
var count = 0
for (pat <- pattern if (!pat.findAllIn(line).isEmpty)){
count += 1
matches += pat.findAllIn(line).toList
}
if (count == 0){
matches += List("NA")
}
}
return matches.toList
}

Your question is not entirely complete, so I can't be sure, but I believe the following will do the job:
for {
line <- caselist
matches = pattern.map(_.findAllIn(line).toList)
} yield matches.flatten match {
case Nil => List("NA")
case ms => ms
}

This should do the job. Using foreach and filter to generate the matches and checking to make sure there is a match for each line will work.
caseList.foreach{ line =>
val results = pattern.foreach ( pat => pat.findAllIn(line).toList )
val filteredResults = results.filter( ! _.isEmpty )
if ( filteredResults.isEmpty ) List("NA")
else filteredResults
}
Functional doesn't mean you can't have intermediate named values.

Related

When to use keyword return in Scala

I learned early on that there is no reason to use the return keyword in Scala (as far as I'm aware). That being said I found an example where simply changing adding the return keyword made my function work, where it previously didn't.
The code in question comes from my solution to the Advent of Code day 7 challenge.
def containsShinyGoldBag(bagContents: Map[String, List[String]], currentBag: String): Boolean = {
val contents = bagContents(currentBag)
if (bagContents(currentBag).contains("shiny gold") ) {
// Base Case: Bag Found in list of bags
true
} else if (contents == List.empty){
// Base Case: Dead End
false
} else {
// Continue searching down list
// Ideal solution ( gives same result as the working solution without return keyword )
// for (b <- contents) containsShinyGoldBag(bagContents, b)
// Working solution
for (b <- contents) {
if (containsShinyGoldBag(bagContents, b)) {
println(s"Found one! $b inside a $currentBag")
return true // <--- culprit
}
else false
}
false
}
}
// In the main function
var count = 0
for (bag <- bagContents.keys) {
if (containsShinyGoldBag(bagContents, bag)) {
count = count + 1
}
}
println(s"There are $count way to bring a shiny gold bag!")
When I run the code without return I end up with count = 7, which is the number of bags directly containing a shiny gold bag, rather than the correct number which counts bags that contain a shiny gold bag somewhere inside of one of their other bags down the line.
A function returns the value of the last expression it evaluates; in your case that will be one of:
true after if (bagContents(currentBag).contains("shiny gold") );
false after else if (contents == List.empty);
the last false.
true is not in such a position, so you need return to, well, make the function return it. Otherwise it's evaluated and ignored because you don't do anything with it. So is else false in the same for, actually, it can be removed without changing the meaning.
The alternative to avoid return here is
contents.exists(b => containsShinyGoldBag(bagContents, b))

SLICK: To insert value in 3 different tables using one slick api call

The question is related to slick:
I have three tables:
1) Users
2)Team2members
3)Team2Owners
In my post request to users, I am passing values of memberOf and managerOf, these values will be inserted in the tables Team2members and Team2Owners respectively and not in Users table. Though other values of the post request will be inserted in 'Users' table.
My Post request looks like below:
{"kind": "via#user",
"userReference":{"userId":"priya16"},
"user":"preferredNameSpecialChar#domain1.com","memberOf":{"teamReference":{"organizationId":"airtel","teamId":"supportteam"}},
"managerOf":{"teamReference":{"organizationId":"airtel","teamId":"supportteam"}},
"firstName":"Special_fn1",
"lastName":"specialChar_ln1",
"preferredName":[{"locale":"employee1","value":"##$%^&*(Z0FH"}],
"description":" preferredNameSpecialChar test "}
I am forming the query which is shown below:
The query seems to work fine when only memberInsert is defined, when I try to define both the values i.e.memberInsert and managerInsert then insertion happens only for second value.
val query = config.api.customerTableDBIO(apiRequest.parameters.organizationId).flatMap { tables =>
val userInsert = tables.Users returning tables.Users += empRow
val memberInsert = inputObject.memberOf.map(m => m.copy(teamReference = m.teamReference.copy(organizationId = apiRequest.parameters.organizationId))).map { r =>
for {
team2MemberRow <- tables.Team2members returning tables.Team2members += Teams2MembersEntity.fromEmtToTeams2Members(r, empRow.id)
team <- tables.Teams.filter(_.id === r.teamReference.teamId.toLowerCase).map(_.friendlyName).result.headOption
} yield (team2MemberRow, team)
}
val managerInsert = inputObject.managerOf.map(m => m.copy(teamReference = m.teamReference.copy(organizationId = apiRequest.parameters.organizationId))).map { r =>
for {
team2OwnerRow <- tables.Team2owners returning tables.Team2owners += Teams2OwnersEntity.fromEmtToTeam2owners(r, empRow.id)
team <- tables.Teams.filter(_.id === r.teamReference.teamId.toLowerCase).map(_.friendlyName).result.headOption
} yield (team2OwnerRow, team)
}
userInsert.flatMap { userRow =>
val user = UserEntity.fromDbEntity(userRow)
if (memberInsert.isDefined) memberInsert.get
.map(r => user.copy(memberOf = Some(Teams2MembersEntity.fromEmtToMemberRef(r._1, r._2.map(TeamEntity.toApiFriendlyName).getOrElse(List.empty)))))
else DBIO.successful(user)
if (managerInsert.isDefined) managerInsert.get
.map(r => user.copy(managerOf = Some(Teams2OwnersEntity.fromEmtToManagerRef(r._1, r._2.map(TeamEntity.toApiFriendlyName).getOrElse(List.empty)))))
else DBIO.successful(user)
}
}
The query seems to work fine when only memberInsert is defined, when I try to define both the values i.e.memberInsert and managerInsert then insertion happens only for second value.
The problem looks to be with the final call to flatMap.
That should return a DBIO[T]. However, your expression generates a DBIO[T] in various branches, but only one value will be returned from flatMap. That would explain why you don't see all the actions being run.
Instead, what you could do is assign each step to a value and sequence them. There are lots of ways you could do that, such as using DBIO.seq or andThen.
Here's a sketch of one approach that might work for you....
val maybeInsertMemeber: Option[DBIO[User]] =
member.map( your code for constructing an action here )
val maybeInsertManager Option[DBIO[User]] =
manager.map( your code for constructing an action here )
DBIO.sequenceOption(maybeInsertMember) andThen
DBIO.sequenceOption(maybeInsertManager) andThen
DBIO.successful(user)
The result of that expression is a DBIO[User] which combines three queries together.

Replacement of if with higher order method

using if block in scala for distributed computing is least recommended. I have code and i want to replace if with Scala higher order method. How can i do that.
Detail code is given Here
Some part of code that contains if block is.
var bat = DenseVector.fill(N)(new BAT12(d , MinVal , MaxVal ))
bat.foreach{x => x.BestPosition = x.position;x.fitness = Sphere(x.position) ; x.BestFitness = x.fitness}
bat.foreach(x =>
if(x.BestFitness < GlobalBest_Fitness)
{
GlobalBest_Fitness =x.BestFitness ;GlobalBest_Position = x.BestPosition
})
Try
bat.filter(_.BestFitness < GlobalBest_Fitness).foreach { x =>
GlobalBest_Fitness = x.BestFitness
GlobalBest_Position = x.BestPosition
}
Do a filter before the foreach, with the if condition as the filter condition. Then do the foreach without any condition.

Simplify Scala loop to one line

How do I simplify this loop to some function like foreach or map or other thing with Scala? I want to put hitsArray inside that filter shipList.filter.
val hitsArray: Array[String] = T.split(" ");
for (hit <- hitsArray) {
shipSize = shipList.length
shipList = shipList.filter(!_.equalsIgnoreCase(hit))
}
if (shipList.length == 0) {
shipSunk = shipSunk + 1
} else if (shipList.length < shipSize) {
shipHit = shipHit + 1
}
To be fair, I don't understand why you are calling shipSize = shipList.length as you don't use it anywhere.
T.split(" ").foreach{ hit =>
shipList = shipList.filter(!_.equalsIgnoreCase(hit))
}
which gets you to where you want to go. I've made it 3 lines because you want to emphasize you're working via side effect in that foreach. That said, I don't see any advantage to making it a one-liner. What you had before was perfectly readable.
Something like this maybe?
shipList.filter(ship => T.split(" ").forall(!_.equalsIgnoreCase(ship)))
Although cleaner if shipList is already all lower case:
shipList.filterNot(T.split(" ").map(_.toLowerCase) contains _)
Or if your T is large, move it outside the loop:
val hits = T.split(" ").map(_.toLowerCase)
shipList.filterNot(hits contains _)

Can this 'if' statement be removed?

I use this code to read file into memory :
val lines = Source.fromFile(fileToRead, "utf-8").getLines
To iterate over some of the lines I use :
lines.take(linesToReadFromDataFile).foreach(line => {
Sometimes I may want to iterate all lines :
lines.foreach(line => {
To determines if to real all of the lines I could use a boolean 'useAlllines' and do something like :
if(useAllLines)
lines.foreach(line => {
else
lines.take(linesToReadFromDataFile).foreach(line => {
Using Scala is there a better way of achieving this ?
I guess this will be enough:
val toIterate =
if(useAllLines)
lines
else
lines.take(linesToReadFromDataFile)
for ( line <- toIterate ) {
...
}
You could also combine useAllLines and linesToReadFromDataFile in a single variable of type Option[Int]:
val toIterate = optionLinesToReadFromDataFile.map{ lines.take(_) }.getOrElse(lines)
lines.take(if (useAllLines) lines.length else linesToReadFromDataFile).foreach(