I have a List of “rules”
tuples as follows:
val rules = List[(A, List[B])]
, where A
and B
are two separate case-classes
For the purposes of my use-case, I need to convert this to an Option[(A, List[B])]
. The A
case class contains a property id
which is of type Option[String]
, based on which the tuple is returned.
I have written a function def findRule(entryId: Option[String])
, from which I intend to return the tuple (A, List[B])
whose A.id = entryId
as an Option. So far, I have written the following snippet of code:
def findRule(entryId: Option[String]) = {
for {
ruleId <- rules.flatMap(_._1.id) // ruleId is a String
id <- entryId // entryId is an Option[String]
} yield {
rules.find(_ => ruleId.equalsIgnoreCase(id)) // returns List[Option[(A, List[B])]
}
}
This snippet returns a List[Option[(A, List[B])]
but I can’t figure out how to retrieve just the Option from it. Using .head()
isn’t an option, since the rules
list may be empty. Please help as I am new to Scala.
Example (the real examples are too large to post here, so please consider this representative example):
val rules = [(A = {id=1, ….}, B = [{B1}, {B2}, {B3}, …]), (A={id=2, ….}, B = [{B10}, {B11}, {B12}, …]), …. ]
(B
is not really important here, I need to find the tuple based on the id
element of case-class A
)
Now, suppose entryId = Some(1)
After the findRule()
function, this would currently look like:
[Some((A = {id=1, …}, B = [{B1}, {B2}, {B3}, …]))]
I want to return:
Some((A = {id=1, …}, B = [{B1}, {B2}, {B3}, …]))
, ie, the Option within the List returned (currently) from findRule()
From your question, it sounds like you're trying to pick a single item from your list based on some conditional, which means you'll probably want to start with rules.find
. The problem then becomes how to express the predicate function that you pass to find
.
From my read of your question, the conditional is
The
id
on theA
part of the tuple needs to match theentryId
that was passed in elsewhere
def findRule(entryId: Option[String]) =
rules.find { case (a, listOfB) => entryId.contains(a.id) }
The case
expression is just nice syntax for dealing with the tuple. I could have also done
rules.find { tup => entryId.contains(tup._1.id) }
The contains
method on Option roughly does "if I'm a Some, see if my value equals the argument; if I'm a None, just return false and ignore the argument". It works as a comparison between the Option[String]
you have for entryId
and the plain String
you have for A
's id
.
Your first attempt didn't work because rules.flatMap
got you a List
, and using that after the <-
in the for-comprehension means another flatMap
, which keeps things as a List.