Reputation:
I've recently been working on a beginner's project in Scala, and have a beginner question about Scala's Lists.
Say I have a list of tuples ( List[Tuple2[String, String]]
, for example). Is there a convenience method to return the first occurence of a specified tuple from the List, or is it necessary to iterate through the list by hand?
Upvotes: 17
Views: 27924
Reputation: 20435
Consider collectFirst
which delivers Some[(String,String)]
for the first matching tuple or None
otherwise, for instance as follows,
xs collectFirst { case t@(a,_) if a == "existing" => t }
Some((existing,str))
scala> xs collectFirst { case t@(a,_) if a == "nonExisting" => t }
None
Using @
we bind the value of the tuple to t
so that a whole matching tuple can be collected.
Upvotes: 1
Reputation: 16898
You could try using find. (Updated scala-doc location of find)
Upvotes: 6
Reputation: 18076
Here's code that may help you.
I had a similar case, having a collection of base class entries (here, A
) out of which I wanted to find a certain derived class's node, if any (here, B
).
class A
case class B(val name: String) extends A
object TestX extends App {
val states: List[A] = List( B("aa"), new A, B("ccc") )
def findByName( name: String ): Option[B] = {
states.find{
case x: B if x.name == name => return Some(x)
case _ => false
}
None
}
println( findByName("ccc") ) // "Some(B(ccc))"
}
The important part here (for my app) is that findByName
does not return Option[A]
but Option[B]
.
You can easily modify the behaviour to return B
instead, and throw an exception if none was found. Hope this helps.
Upvotes: 1
Reputation: 61434
If you're learning scala, I'd take a good look at the Seq trait. It provides the basis for much of scala's functional goodness.
Upvotes: 2
Reputation:
You could also do this, which doesn't require knowing the field names in the Tuple2 class--it uses pattern matching instead:
list find { case (x,y,_) => x == "C" && y == "D" }
"find" is good when you know you only need one; if you want to find all matching elements you could either use "filter" or the equivalent sugary for comprehension:
for ( (x,y,z) <- list if x == "C" && y == "D") yield (x,y,z)
Upvotes: 1
Reputation: 55123
As mentioned in a previous comment, find
is probably the easiest way to do this. There are actually three different "linear search" methods in Scala's collections, each returning a slightly different value. Which one you use depends upon what you need the data for. For example, do you need an index, or do you just need a boolean true
/false
?
Upvotes: 3
Reputation: 13809
scala> val list = List(("A", "B", 1), ("C", "D", 1), ("E", "F", 1), ("C", "D", 2), ("G", "H", 1)) list: List[(java.lang.String, java.lang.String, Int)] = List((A,B,1), (C,D,1), (E,F,1), (C,D,2), (G,H,1)) scala> list find {e => e._1 == "C" && e._2 == "D"} res0: Option[(java.lang.String, java.lang.String, Int)] = Some((C,D,1))
Upvotes: 13