Reputation: 6548
I have a List of Students from which I want to find the last matching student whose age is 23.
I know that find()
method gives us the first matching occurrence as shown below:
case class Student(id: Int, age: Int)
val students = List(Student(1, 23), Student(2, 24), Student(3, 23))
val firstStudentWithAge23 = students.find(student => student.age == 23)
// Some(Student(1, 23))
This code gives me the first matching student. But I need the last matching student.
For now, I am using reverse
method followed by find
:
val lastStudentWithAge23 = students.reverse.find(student => student.age == 23)
// Some(Student(3,23))
This gives me the last matching student.
But this doesn't not seem to be a good approach since the whole list has to be reversed first. How can I achieve this in a better yet functional way ?
Upvotes: 7
Views: 3943
Reputation: 382
As of Scala 2.13, you can use findLast
to find the last element of a Seq
satisfying a predicate, if one exists:
val students = List(Student(1, 23), Student(2, 24), Student(3, 23))
students.findLast(_.age == 23) // Option[Student] = Some(Student(3, 23))
Upvotes: 12
Reputation: 20415
Yet another approach, using partition
, for instance as follows,
val (l, _) = list.partition(_.age == 23)
l.lastOption
which delivers the list bisected into a tuple of those aged 23 in order of occurrence in the original list, and the rest. From the first tuple take the last item.
Upvotes: 2
Reputation: 23502
chengpohi
's and jwvh
's answers work, but will traverse the list twice or more.
Here's a generic way to find the last occurence that will only traverse the list once:
def findLast[A](la: List[A])(f: A => Boolean): Option[A] =
la.foldLeft(Option.empty[A]) { (acc, cur) =>
if (f(cur)) Some(cur)
else acc
}
We walk through the collection exactly once and always take the last element that matches our predicate f
.
Upvotes: 6
Reputation: 51271
list.lift(list.lastIndexWhere(_.age == 23))
Indexing on a List
isn't optimum, but it's an option.
Upvotes: 2
Reputation: 14217
I think maybe you can achieve this by filter
with lastOption
, like:
list.filter(student => student.age == 23).lastOption
Upvotes: 5