Отфильтровать гетерогенный список по типу - PullRequest
0 голосов
/ 28 декабря 2018

У меня есть начальный список, который состоит из различных типов элементов, и я должен отфильтровать его, чтобы просто взять значения типа 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 голосов
/ 29 декабря 2018

Как академическое упражнение это довольно глупо.Вы должны научиться избегать подобных ситуаций, а не пытаться справиться с этим.Тем не менее, плохой код иногда может быть довольно поучительным.

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))
0 голосов
/ 28 декабря 2018

Один из возможных вариантов - поместить тип результата в 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)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...