Reputation: 303
I have a ByteString
that is containing the representation of Float
s. Each Float
is represented by 3 bytes in the ByteString
.
I need to do some processing on the Float
values, so I would like to perform that processing on an Vector
of Float
values. What would be the best way to do this?
I have a function toFloat :: [Word8] -> Float
that converts 3 bytes of the ByteString
to a Float. So I was thinking of iterating over the ByteString
in steps of 3 Bytes and converting every step to a Float
for a vector
.
I've looked at the library functions for Vector
but I can't find anything that suits this purpose. Data.Vector.Storable.ByteString.byteStringToVector
looked promising but it converts every byte (instead of every 3 bytes) and doesn't give me any control over how the conversion of ByteString
to Float
should happen.
Upvotes: 7
Views: 623
Reputation: 89053
Just use Data.Vector.generate
:
V.generate (BS.length bs `div` 3) $ \i ->
myToFloat (bs BS.! 3*i) (bs BS.! 3*i+1) (bs BS.! 3*i+2)
It'll allocate the vector all at once, and populate it. Data.ByteString.!
is O(1), so this is quite efficient.
Upvotes: 5
Reputation: 91897
Try using
splitAt :: Int -> ByteString -> (ByteString, ByteString)
to split the ByteString into two: one of exactly 3 characters, and another containing the rest of the input. You can use this to implement a recursive function that will give you all the groups of length 3 (similar to Data.List.Split.chunksOf
), and then you can use unpack
on each to get the [Word8]
you need. Pass that through your toFloat
function, and convert to a vector with Vector.fromList
.
There are a number of steps there that seem like perhaps they could be expensive, but I think probably the compiler is smart enough to fuse some of them, like the unpack/fromList pair. And splitting a ByteString is O(1), so that part's not as expensive as it looks either. Seems like this ought to be as suitable an approach as any.
Upvotes: 2