2015-12-06 10 views
5

Ich möchte auf verschiedene Segmente eines list in scala auf den Typen des head und tailpattern match:Wie Muster Kopf und Schwanz Typen einer Skala Liste Muster?

class Solution07 extends FlatSpec with ShouldMatchers { 
    "plain recursive flatten" should "flatten a list" in { 
    val list1 = List(List(1, 1), 2, List(3, List(5, 8))) 
    val list1Flattened = List(1, 1, 2, 3, 5, 8) 

    flattenRecur(list1) should be (list1Flattened) 
    } 

    def flattenRecur(ls: List[Any]): List[Int] = ls match { 
    case (head: Int) :: (tail: List[Any]) => head :: flattenRecur(tail) 
    case (head: List[Int]) :: (tail: List[Any]) => head.head :: flattenRecur(head.tail :: tail) 
    case (head: List[Any]) :: (tail: List[Any]) => flattenRecur(head) :: flattenRecur(tail) // non-variable type... on this line. 
    } 
} 

ich:

Error:(18, 17) non-variable type argument Int in type pattern List[Int] (the underlying of List[Int]) is unchecked since it is eliminated by erasure case (head: List[Int]) :: (tail: List[Any]) => head.head :: flattenRecur(head.tail :: tail) ^

Was bin ich? Wie ist es möglich für mich, Muster auf die head und tail 's Typen der Liste?

+1

versuchen ersetzen 'case (head: Liste [Int]) :: (tail: Liste [Any]) =>' mit 'case ((headhead: Int) :: (headtail: Liste [Beliebige])) :: (tail: List [Any]) => 'Das würde Ihnen erlauben, den Schreibvorgang zu löschen – ayvango

+0

Das Problem ist für die Zeile' case (head: Liste [Any]) :: (tail: List [Any]) 'Sie haben a erwähnt andere Linie, soll das auch dieser Linie helfen ??? – Jas

+1

die dritte Wahl steht im Konflikt mit der zweiten. Sie können also entweder die zweite oder die dritte Wahl einstellen. Da die dritte Wahl allgemeiner ist, ist es leichter, die zweite genauere – ayvango

Antwort

6

Ich bin damit einverstanden, dass @Andreas Lösung mit hList ein schönes Beispiel ist das Problem zu lösen, aber ich verstehe immer noch nicht, was ist das Problem mit diesem:

def flatten(ls: List[_]): List[Int] = ls match { 
    case Nil => Nil 
    case (a: Int) :: tail => a :: flatten(tail) 
    case (a: List[_]) :: tail => flatten(a) ::: flatten(tail) 
    case _ :: tail => flatten(tail) 
    } 

Dann:

println(flatten(List(List("one",9,8),3,"str",4,List(true,77,3.2)))) // List(9, 8, 3, 4, 77) 

Ich sehe keine Probleme beim Löschen von Text in Ihrer Aufgabe, weil Sie die Typen, die gelöscht werden, eigentlich nicht testen müssen. Ich habe absichtlich alle gelöschten Typen in meinem Beispiel übersprungen - um das zu zeigen. Typ löscht nicht die Typinformation der Elemente der Liste, es löscht nur die Typinformation der Liste generisch, die Sie in meinem Fall Any oder _ haben - so brauchen Sie das gar nicht. Wenn ich etwas nicht verpasse, werden in Ihrem Beispiel die Typen überhaupt nicht gelöscht, weil Sie ohnehin fast überall Any haben.

+1

Sie haben Recht mit dieser Beobachtung :) sollte ich die Antwort anpassen? –

+1

Vielleicht würde ich einfach die Aussage über Typ löschen entfernen. Ich denke, der Vorschlag, 'HList' zu verwenden, ist eine gute Alternative, aber ich denke nicht, dass es die einzige Option ist - man kann ohne sie leben. – Archeg

+1

Und ich sollte wahrscheinlich erwähnen, dass ich noch nicht formlos verwendet habe, so bin ich nicht Autorität bei der Entscheidung, ob es gut Ansatz – Archeg

1

Aufgrund der Typenlöschung können Sie jedes Element überprüfen.

def flattenRecur(ls: List[Any]): List[Int] = ls match { 
    case head :: tail if (head.isInstanceOf[Int]) 
        => head.asInstanceOf[Int] :: flattenRecur(tail) 
    case head :: tail if (head.isInstanceOf[List[Any]]) 
        => flattenRecur(head.asInstanceOf[List[Any]]) ++ 
         flattenRecur(tail) 
    case _ :: tail => flattenRecur(tail) 
    case _ => Nil 
} 

Welche Arbeit erscheint:

scala> flattenRecur(List(List("one",9,8),3,"str",4,List(true,77,3.2))) 
res8: List[Int] = List(9, 8, 3, 4, 77) 

Aber als Faustregel, die Vermeidung Any in der Regel ist die Mühe wert.

+0

Ich wünschte, ich könnte "any" vermeiden, aber wenn ich definiert "val list1 = Liste (Liste (1, 1), 2, Liste (3, Liste (5, 8)))' dann ist sein Typ bereits 'List [Any]' kann alles getan werden, um einen anderen Typ dafür zu haben, der mich weiter von der 'type radiation' retten würde? – Jas

1

Sie werden von Einschränkungen durch das Objektsystem gegeben getroffen:

Der einzige gemeinsame Elternteil für List[Int] und Int ist Any

So zu verdanken, dass das System Inferenz nur sicher davon ausgehen kann, dass Sie Any zurückkehren können. Die vorgeschlagene Lösung @jwvh ist machbar, birgt jedoch die Gefahr von Laufzeitausnahmen.

Wenn Sie das Problem auf eine Art und Weise eine typsichere Option lösen wollen könnte HList die unförmigen Bibliothek zu benutzen, https://github.com/milessabin/shapeless: https://github.com/milessabin/shapeless/wiki/Feature-overview:-shapeless-2.0.0#heterogenous-lists

+1

Könnten Sie sich bitte mein Beispiel in der Antwort unten anschauen? Ich glaube nicht, dass (2) wahr ist - die Sequenz kennt die Arten der Elemente, die sich darin befinden. Es weiß nicht nur, dass es "T" ist, das für die Aufgabe nicht benötigt wird. Ich stimme zu "HList" sind großartig und sie sind eine der möglichen Optionen, wie dies zu lösen, aber das ist nicht die einzige Option – Archeg

+0

Für Ihre erweiterte Antwort ist dies völlig richtig. Das Löschen des Typs betrifft Sie nicht. –