17

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?

7 Answers 7

13
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))
Sign up to request clarification or add additional context in comments.

4 Comments

Is it possible to return not Some((C,D,1)) but (C,D,1)? I mean the same way if I would use list(1).
@grass What should the return value be if the triple (C,D,1) is not found in the list?
None or exception or empty set. Would be great if there is a way to customize the return value if the triple is not found(except writing my own find() method).
'None' and 'Some' always go together. They make an 'Option[T]'. If your function were to simply return 'T' you have to signal the no-such case by an exception. I'll add an answer soon that I think provides what you're wanting (using 'find').
6

You could try using find. (Updated scala-doc location of find)

Comments

3

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?

2 Comments

Could you give more information on these "linear search" methods? I'm looking to get the index of a tuple (having only part of the tuple)
actually I've found what I was looking for: .zipWithIndex.collect { case ("partOfTuple", _, i) => i }
2

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.

Comments

1

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)

1 Comment

Your second example seems to function much more like filter, i.e. it will return all elements matching property, not the only first one as question author wants it to.
1

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.

Comments

1

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.