2017-01-25 6 views
4

Ich habe eine ByteString, die die Darstellung von Float s enthält. Jeder Float wird durch 3 Bytes in ByteString dargestellt.ByteString zu Vector Konvertierung

Ich brauche etwas Verarbeitung auf die Float Werte, so würde ich gerne diese Verarbeitung auf einem Vector von Float Werte durchführen. Was wäre der beste Weg, dies zu tun?

Ich habe eine Funktion toFloat :: [Word8] -> Float, die 3 Bytes des ByteString in einen Float konvertiert. Also überlegte ich, über die ByteString in Schritten von 3 Bytes zu iterieren und jeden Schritt in eine Float für eine vector zu konvertieren.

Ich habe die Bibliothek Funktionen für Vector angeschaut, aber ich kann nichts finden, das diesem Zweck entspricht. Data.Vector.Storable.ByteString.byteStringToVector sah vielversprechend aus, aber es konvertiert jedes Byte (statt alle 3 Bytes) und gibt mir keine Kontrolle darüber, wie die Konvertierung von ByteString zu Float passieren sollte.

Antwort

2

Nur Data.Vector.generate verwenden:

V.generate (BS.length bs `div` 3) $ \i -> 
    myToFloat (bs BS.! 3*i) (bs BS.! 3*i+1) (bs BS.! 3*i+2) 

Es wird der Vektor auf einmal zuweisen und es füllen. Data.ByteString.! ist O (1), also ist das ziemlich effizient.

+2

das ist fast doppelt so schnell wie die "entfalteten" Versionen, die ich ausprobiert habe. http://sprung.us/cjfe – Michael

2

Versuchen unter Verwendung von

splitAt :: Int -> ByteString -> (ByteString, ByteString) 

die ByteString in zwei aufgeteilt: eine von genau 3 Zeichen, und ein anderer, den Rest des Eingangs enthält. Sie können dies verwenden, um eine rekursive Funktion zu implementieren, die Ihnen alle Gruppen der Länge 3 (ähnlich Data.List.Split.chunksOf) gibt, und dann können Sie unpack auf jedem verwenden, um die [Word8] zu erhalten, die Sie benötigen. Übergeben Sie das durch Ihre toFloat-Funktion, und konvertieren Sie in einen Vektor mit Vector.fromList.

Es gibt eine Reihe von Schritten, die scheinen, als ob sie vielleicht teuer sein könnten, aber ich denke, dass der Compiler intelligent genug ist, einige von ihnen zu fusionieren, wie das Paar entpacken/fromList. Und ein ByteString zu teilen ist O (1), so dass ein Teil nicht so teuer ist, wie es aussieht. Scheint so, als ob dieser Ansatz genauso geeignet sein sollte wie jeder andere.

+2

Sie können ['Data.Vector.unfold :: (b -> Vielleicht (a, b)) -> b -> Vektor a'] (https://hackage.haskell.org/package/vector- 0.12.0.0/docs/Data-Vector.html#g:10) um dies direkt zu implementieren - 'V.unfold (\ bs -> let (fs, bs)) = BS.splitAt 3 bs in if BS.length fs/= 3 dann Nothing else Nur (myToFloat fs, bs ')) ' – rampion

+1

Es könnte sich lohnen, zu @rampions Bemerkung hinzuzufügen, dass' Entfalten' eine besonders gute Möglichkeit ist, einen 'Data.Vector.Unboxed.Vector' zu konstruieren wird mit jedem geeigneten Verbraucher verschmelzen. Es entspricht dem zugrundeliegenden Stream-Typ. Ob das wichtig ist, hängt davon ab, was Sie mit dem Vektor machen werden, sobald Sie ihn bekommen haben. – Michael

+0

Das sieht furchtbar teuer aus. Splitting könnte O (1) sein, aber wenn n/3 geteilt wird, ergibt sich immer noch O (n) zum Teilen, O (n) zum Entpacken und O (n) für 'fromList'. Ich werde es versuchen. – Valerie94