2016-05-06 3 views
0

Ich versuche einen Vektor mit Subvektoren zu erstellen, die aus Elementen bestehen, die aus einem anderen Vektor mit Hilfe eines Vektors von Subvektorindizes entnommen wurden. Jedes Element in b entspricht dem Sub-Vektor-Index, den die Elemente in a haben sollten, wenn sie in c eingegeben werden.Haskell create vector with subvectors using indexes

import Data.Vector 
let a = fromList [9,2,3,7,4,1,8,5] 
let b = fromList [3,3,2,0,1,1,2,2] 
let c = fromList [ a ! k | k <- b ] 
Expected c = [[7],[4,1],[3,8,5],[9,2]] 

Ich bin ein bisschen stecken, wird der Fehler immer

"konnte nicht mit den tatsächlichen Typ Vector Integer in Anw Liste Verständnis k < erwarteten Typ [Int] match - b"

+0

Sie [ 'backpermute'] suchen sind (https://hackage.haskell.org/package/vector-0.11.0.0/candidate/docs/ Daten-Vektor.html # g: 17)? –

+0

Nein, der Indexvektor enthält in Backpermute die Indizes der Werte, die aus 'a' genommen werden sollten, aber mein Indexvektor 'b' enthält die Unterlistenindizes, in die die Elemente eingefügt werden sollen. – tsorn

+0

Ziemlich sicher, dass Sie dieses Verhalten nicht bekommen werden, ohne sich selbst mit ST und intermediären mutablen Vektoren zu beschäftigen; Ich würde nicht erwarten, dass das eingebaut wird. –

Antwort

4

Dies funktioniert nicht, da b ist ein Vektor, keine Liste:

k <- b 

Allerdings kann diese Arbeit:

[ ... | k <- toList b ] 

nächstes die Art der a und b ist Vector Integer und der ! Operator nimmt eine Int. Sie müssen also den Index konvertieren fromInteger mit:

let c = fromList [ a ! fromInteger k | k <- toList b] 

aktualisieren

Hier ist ein Weg, um die Transformation ohne wiederholt auszuführen geht über die Felder:

import Data.List 

fst3 (b,_,_) = b 
third (_,_,a) = a 

doit :: Vector Int -> Vector Int -> [[Int]] 
doit av bv = [ map third g | g <- groups ] 
    where 
    triples = zip3 (V.toList bv) [1..] (V.toList av) 
    groups = groupBy (\s t -> fst3 s == fst3 t) $ sort triples 

Dies ist im Grunde ein Schwartzian Transform mit einer groupBy nach dem Sortierschritt hinzugefügt. Die Sortierung auf den Tripeln erfolgt in der kanonischen Art - eine Lex-Sortierung an der ersten Koordinate, gefolgt von der zweiten Koordinate, gefolgt von der dritten Koordinate.

Es gibt auch andere Möglichkeiten, den Ausdruck für groups zu schreiben:

import Data.Funcition (on) 
import GHC.Exts (groupWith) 

    ... 
    groups = groupBy (on (==) fst3) $ sort triples 
    groups = groupWith fst3 triples 

Beachten Sie, dass groupBy erfordert, dass die Tripel sortiert werden, während groupWith nicht.

+0

Obwohl dies den Fehler beseitigt, ist das Ergebnis nicht das, was ich angestrebt habe. Jede Zahl in "a" sollte zu einem Untervektor in "c" mit dem in "b" angegebenen Index hinzugefügt werden. Z.B. a [0] sollte in c [b [0]] sein. – tsorn

0

Mit Hilfe ErikR kam ich mit auf den Punkt:

let c = fromList [fromList [a ! i | i <- [0..Data.Vector.length b-1], (b ! i)==j] | j <- [0..Data.Vector.maximum(b)]] 

Es funktioniert, aber es ist nicht schön, besser?

+0

Ok - ich verstehe die Transformation jetzt. Ich habe meine Antwort aktualisiert. – ErikR

0

Es sieht aus wie das, was Sie wollen wahrscheinlich

accumulate (flip (:)) (replicate n []) (zip b a) 

würde ... obwohl Sie explizit haben werden zu n berechnen, vielleicht als maximum b + 1.

0

Mit Listen scheint dies die Logik zu sein

> map (map snd) $ groupBy ((==) `on` fst) $ sortBy (comparing fst) $ zip b a 

[[7],[4,1],[3,8,5],[9,2]]