Cannot prove that Unit <:< (T, U)

后端 未结 3 743
感情败类
感情败类 2021-01-05 05:57

When trying to remove all Unit - () from a list, I tried to call toMap.

scala> List((), ()).filter(_ != ()).toMap


        
相关标签:
3条回答
  • 2021-01-05 06:03

    It means that the type of an element in the list can't be viewed as a tuple which is required to build a Map. A Map in a sense is a collection of tuples (and more).

    Illustration:

    scala> List(1).toMap
    <console>:8: error: Cannot prove that Int <:< (T, U).
              List(1).toMap
                      ^
    scala> List(1 -> 2).toMap
    res1: scala.collection.immutable.Map[Int,Int] = Map(1 -> 2)
    

    I can build a map from a list of tuples, but not from a list of single cardinality elements.

    Maybe you mean to say .map instead of .toMap? ;)

    0 讨论(0)
  • 2021-01-05 06:11

    Ah! Now your other question makes a little more sense. Still not sure what you're doing to produce this mixed Unit/Tuple2 list though.

    This should work:

    List((), (), (3,4)).collect { case t@(_: Int, _: Int) => t }.toMap
    

    Note that I'm using variable binding here (binding the match to t) to return the same Tuple2 instance we matched rather than creating a new one.

    By using collect you convert the type of your list from List[Any] to List[(Int, Int)], which is what toMap wants since it's expecting some List[(A,B)].


    Note: Although this answer should work for you, I still think your design is flawed. You'd be better off fixing the underlying design flaw rather than treating the symptoms like this.

    It looks like this would be a good fit for using Scala's Option type. In this case, your sample list would become List(None, None, Some((3,4))), or you could write it as List(None, None, Some(3->4)) for readability (nested parenthesis like that can get confusing).

    If you use Option then the type of your list becomes List[Option[(Int, Int)]], which should be much nicer to deal with than a List[Any]. To get rid of the None entries and get the desired List[(Int,Int)] you can just call flatten:

    List(None, None, Some(3->4)).flatten
    // res0: List[(Int, Int)] = List((3,4))
    List(None, None, Some(3->4)).flatten.toMap
    // res1: scala.collection.immutable.Map[Int,Int] = Map(3 -> 4)
    

    However, it would be even better if you can avoid putting the None entries in your list in the first place. If you're producing this list using a Scala for comprehension, you could use a guard in your for expression to remove the invalid elements from the output.

    0 讨论(0)
  • All in one go:

    scala> val l2 = List(1 -> 3, (), 4 -> 4, (), 9 -> 4, (), 16 -> 7)
    l2: List[Any] = List((1,3), (), (4,4), (), (9,4), (), (16,7))
    
    scala> (l2 collect { case (a, b) => (a, b) }).toMap
    res4: scala.collection.immutable.Map[Any,Any] = Map(1 -> 3, 4 -> 4, 9 -> 4, 16 -> 7)
    

    Better typed:

    scala> (l2 collect { case (i: Int, j: Int) => (i, j) }).toMap
    res5: scala.collection.immutable.Map[Int,Int] = Map(1 -> 3, 4 -> 4, 9 -> 4, 16 -> 7)
    
    0 讨论(0)
提交回复
热议问题