-1

I would like to cast scala collection types, such as Seq[Any] to Seq[(String, String)], without it producing a Warning.

Example code:

val seqs: Seq[Any] = Seq("1" -> "a", "2" -> "b")

def func(seqs: Seq[(String, String)]): String = {
}

func(seqs.asInstanceOf[Seq[(String, String)]]) // this will be warning

EDIT on 2018-10-18:

For a better understanding my question, here is my real case: I have a function to process something with a parameter Seq[Any], actually, I wish this parameter's type is Seq[Int] or Seq[(String, String)]:

def getColumns(specifiedSegs: Seq[Any] = Seq.empty): Set[(String, String)] = {
  if (specifiedSegs.isEmpty) {
    // load all kvs from api
    loadAllFromMetaApi() // this will return a Set[(String, String)]
  } else {
    specifiedSegs.head match {
      case _: Int => ... // let's omission this
      case _: (String, String) => specifiedSegs.asInstanceOf[Seq[(String, String)]].toSet // warning!
    }
  }
}

and when I build the project, it prints the warning on specifiedSegs.asInstanceOf[Seq[(String, String)]].toSet: warning: non-variable type argument String in type pattern (String, String) is unchecked since it is eliminated by erasure

RAGHHURAAMM
  • 1,099
  • 7
  • 15
cceasy
  • 193
  • 1
  • 8
  • Can you please give the code that you tried out ? – Chaitanya Oct 17 '18 at 09:29
  • You need to be more detailed than this also give use the code where you're having issues with. – S4NDM4N Oct 17 '18 at 09:39
  • It is not specifically mentioned what do you want? Just showing example code without asking anything about the issue faced will not suffice. Please be specific about your requirement or the clarification what you want. – RAGHHURAAMM Oct 17 '18 at 09:45
  • val seqs: Seq[Any] = Seq("1" -> "a", "2" -> "b") this is Seq(String,String) why you want to convert it? – Raman Mishra Oct 17 '18 at 10:21
  • Sorry for the blurred question description, I update my case for better understand. – cceasy Oct 18 '18 at 02:56

2 Answers2

2

Using asInstanceOf is not really recommended. You can use a function to achieve smoother type conversion:

def seqOfAnyToSeqString(param : Seq[Any]) : Seq[(String, String)]
 = param.collect {
  case (x, y) => (x.toString, y.toString)
}

To test this function:

val a  = Seq(1,2,3, 4 -> "b")
seqOfAnyToSeqString(a)

Outputs:

a: Seq[Any] = List(1, 2, 3, (4,b))
res0: Seq[(String, String)] = List((4,b))

So it will silently ignore those elements in the sequence which are not defined as tuples but converts all tuples to tuples of string. I, of course, assume that the input is fairly simple and a simple .toString will suffice.

EDIT:

Alternatively, as suggested in the comments, if you are absolutely sure that the sequence is an instance of Seq[(String, String)], you could write the above function -using type ascriptions - as:

def seqOfAnyToSeqString(param : Seq[Any]) : Seq[(String, String)]
     = param.collect {
      case (x : String, y : String) => (x, y)
    }

But note that this will drop elements if they do not conform to (String, String).

jrook
  • 3,459
  • 1
  • 16
  • 33
  • 1
    or `case (x: String, y: String) => (x, y)` – dyrkin Oct 17 '18 at 10:10
  • @dyrkin, It gives `List()` for an input such as: `Seq(0, 1->1,2.3->"c",true->false, 4 -> "b")` while the given answer takes care of such cases. The OP has not really specified what they want and your suggestion will work too for the case in the question. – jrook Oct 17 '18 at 10:14
  • I think what dyrkin commented ie., `case (x: String, y: String) => (x, y)` is better becoz it will not again attempt to convert to toString if the tuple is already conforming to tuple of strings. The conversion to toString is redundant. – RAGHHURAAMM Oct 17 '18 at 10:53
  • @RAGHHURAAMM: updated the answer to cover that case, too. – jrook Oct 17 '18 at 11:46
0

If you want to ignore all non-(String, String) elements, see jrook's answer. As an alternative, here's a way to do it if you want to throw a specific error when you come across a non-(String, String) element:

def convertSeq(seq: Seq[Any]): Seq[(String, String)] = seq map {
  case (x: String, y: String) => (x, y)
  case x => throw new IllegalArgumentException(s"$x is not type (String, String)")
}

eg:

scala> def convertSeq(seq: Seq[Any]): Seq[(String, String)] = seq map {
     |   case (x: String, y: String) => (x, y)
     |   case x => throw new IllegalArgumentException(s"$x is not type (String, String)")
     | }
convertSeq: (seq: Seq[Any])Seq[(String, String)]

scala> convertSeq(Seq(("abc", "def"), ("ghi", "jkl")))
res0: Seq[(String, String)] = List((abc,def), (ghi,jkl))

scala> convertSeq(Seq(1, 2, 3))
java.lang.IllegalArgumentException: 1 is not type (String, String)
  at $anonfun$convertSeq$1.apply(<console>:13)
  at $anonfun$convertSeq$1.apply(<console>:11)
  at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:245)
  at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:245)
  at scala.collection.immutable.List.foreach(List.scala:381)
  at scala.collection.TraversableLike$class.map(TraversableLike.scala:245)
  at scala.collection.immutable.List.map(List.scala:285)
  at .convertSeq(<console>:11)
  ... 33 elided
James Whiteley
  • 3,363
  • 1
  • 19
  • 46