I am a novice in working with Scala.
I have a Scala Vector
containing Person
objects on which I need to loop on and pass each element of the Vector to a method personCollector
whose return value too is a Vector. As can be seen in the Scala REPL output below of for
loop it prints the Vector returned by personCollector
three times which is because the people
Vector contains three entries.However I would like to print the Vector returned by personCollector
only once i.e. after the for loop iteration is over.
In Java I could do it following way:
var peopleWithFirstName = null;
for (Person p : people)
peopleWithFirstName = firstNameCollector(p);
System.out.println(peopleWithFirstName);
However I cannot figure out to do the above in Scala.Below is my Scala code.
Welcome to Scala version 2.10.4 (Java HotSpot(TM) Server VM, Java 1.7.0_04).
Type in expressions to have them evaluated.
Type :help for more information.
scala> case class Person(
| firstName: Option[String],
| middleName: Option[String],
| lastName: Option[String] )
defined class Person
scala> def isFirstNameValid(person: Person) = person.firstName.isDefined
isFirstNameValid: (person: Person)Boolean
scala> def personCollector(isValid: (Person) => Boolean) = {
| var validPeople = Vector[Person]()
| (person: Person) => {
| if(isValid(person)) validPeople = validPeople :+ person
| validPeople
| }
| }
personCollector: (isValid: Person => Boolean)Person => scala.collection.immutable.Vector[Person]
scala> val p1 = Person(Some("First Name"), Some("Middle Name"), Some("Last Name"))
p1: Person = Person(Some(First Name),Some(Middle Name),Some(Last Name))
scala> val p2 = Person(None, Some("Middle Name"), None)
p2: Person = Person(None,Some(Middle Name),None)
scala> val p3 = Person(Some("First Name"), None, None)
p3: Person = Person(Some(First Name),None,None)
scala> val people = Vector(p1, p2, p3)
people: scala.collection.immutable.Vector[Person] = Vector(Person(Some(First Name),Some(Middle Name),Some(Last Name)), Person(None,Some(Middle Name),None), Person(Some(First Name),None,None))
scala> val firstNameCollector = personCollector(isFirstNameValid)
firstNameCollector: Person => scala.collection.immutable.Vector[Person] = <function1>
scala> for (p <- people)
| println(firstNameCollector(p))
Vector(Person(Some(First Name),Some(Middle Name),Some(Last Name)))
Vector(Person(Some(First Name),Some(Middle Name),Some(Last Name)))
Vector(Person(Some(First Name),Some(Middle Name),Some(Last Name)), Person(Some(First Name),None,None))
Thanks.
I'm not entirely sure what your actual goal is. I guess what you are trying to achieve seem to be better solved by filter
and map
:
filter
serves as validator in this case, i.e., people.filter(isFirstNameValid)
. This returns a collection of all people with a defined first name -- is this what you want?map
serves as extractor of the desired field, in this case the first name. So overall people.filter(isFirstNameValid).map(_.firstName)
in case you want your collection to represent first names instead of a complete person. If you furthermore want to convert from Option
(of first name) to a concrete value you may want to use flatMap
instead (this also makes the explicit validation unnecessary).In case you really what to stick to a solution based on modifying external state, you have to place your mutable variable in an external scope for instance...