过滤类型的异构列表

时间:2018-12-28 18:49:29

标签: scala list casting

我有一个包含不同类型元素的初始列表,我必须对其进行过滤以仅采用int和double值。

例如(1 :: "hello" :: 100 :: 3.14 :: ('a'::10::Nil) :: 'c' :: (5,7,'a') :: Nil)应该变成(1, 100, 3.14, List(10), (5,7))

我想出一个解决方案很麻烦,因为一旦将列表传递给方法,它就变成了List [Any]类型的列表,在转换之前我需要知道每个元素的类型。它不包含其他子结构(例如元组),这不是问题,因为我可以通过模式匹配来管理某些事情。

是否可以通过某种方式获取Any元素的特定类型并将其强制转换?

2 个答案:

答案 0 :(得分:2)

作为学术活动,这很愚蠢。您应该学习如何避免这种情况,而不是尝试应对。尽管如此,错误的代码有时还是很有启发性的。

def intOrDbl(la :List[Any]) :List[Any] = la.flatMap{
    case i:Int     => List(i)
    case d:Double  => List(d)
    case l:List[_] => List(intOrDbl(l))
    case t:Product => val res = intOrDbl(t.productIterator.toList)
                      res.length match {
                        case 0 => Nil
                        case 1 => List(res)
                        case 2 => List((res(0),res(1)))
                        case 3 => List((res(0),res(1),res(2)))
                        case 4 => List((res(0),res(1),res(2),res(3)))
                        // etc.
                      }
    case _ => Nil
}

val data = 1 :: "hello" :: 100 :: 3.14 :: ('a'::10::Nil) :: 'c' :: (5,7,'a') :: Nil
intOrDbl(data)
//res0: List[Any] = List(1, 100, 3.14, List(10), (5,7))

答案 1 :(得分:1)

您可以选择的一种方法是将结果类型放入ADT中。这是可能的工作方式:

sealed trait IntOrDoubleOrList
case class IntValue(value: Int) extends IntOrDoubleOrList
case class DoubleValue(value: Double) extends IntOrDoubleOrList
case class ListValue(value: List[IntOrDoubleOrList]) extends IntOrDoubleOrList

def filterIntOrDouble(l: List[_]): List[IntOrDoubleOrList] = {
  l.collect({
    case iv: Int => IntValue(iv)
    case dv: Double => DoubleValue(dv)
    case lv: List[_] => ListValue(filterIntOrDouble(lv))
  })
}

def test(): Unit = {
  val origList = (1 :: "hello" :: 100 :: 3.14 :: ('a' :: 10 :: Nil) :: 'c' :: (5, 7, 'a') :: Nil)

  val f = filterIntOrDouble(origList)
  println(f)
}

根据您的进一步需求,您可以使用IntOrDoubleOrList之类的一些辅助方法来扩展foreach(intHandler: Int => Unit, doubleHandler: Double => Unit)性状