“去隔行” Scala 中的列表
我有一个字节列表,表示从音频接口读取的原始样本。根据用例和硬件,每个样本的长度可以是 1 到 4 个字节,并且“流”中的通道总数可以或多或少是任意的。每个样本的通道数量和位数在运行时都是已知的。
我将举一个例子来说明我的意思。流中有四个通道,每个样本是两个字节。
列表(A1,A2,B1,B2,C1,C2,D1,D2,A3,A4,B3,B4,C3,C4,D3,D4)
所以A1
是通道A第一个样本的第一个字节,A2
是同一样本的第二个字节,依此类推。
我需要做的是将每个通道的样本提取到自己的列表中,如下所示:
List(List(A1, A2, A3, A4), List(B1, B2, B3, B4), List(C1, C2) , C3, C4), List(D1, D2, D3, D4))
我将如何在惯用的 Scala 中做到这一点?我几个小时前刚刚开始学习 Scala,我想出的唯一非命令式解决方案显然不是最佳的:
def uninterleave(samples: Array[Byte], numChannels: Int, bytesPerSample: Int) = {
val dropAmount = numChannels * bytesPerSample
def extractChannel(n: Int) = {
def extrInner(in: Seq[Byte], acc: Seq[Byte]): Seq[Byte] = {
if(in == List()) acc
else extrInner(in.drop(dropAmount), in.take(bytesPerSample) ++ acc)
}
extrInner(samples.drop(n * bytesPerSample), Nil)
}
for(i <- 0 until numChannels) yield extractChannel(i)
}
I have a list of bytes that represent raw samples read in from an audio interface. Depending on the use case and H/W, each sample can be anywhere from 1 to 4 bytes long, and the total number of channels in the "stream" can be more or less arbitrary. The amount of channels and bits per sample are both known at runtime.
I'll give an example of what I mean. There are four channels in the stream and each sample is two bytes.
List(A1, A2, B1, B2, C1, C2, D1, D2, A3, A4, B3, B4, C3, C4, D3, D4)
so A1
is the first byte of channel A's first sample, A2
is the second byte of the same sample and so on.
What I need to do is extract each channel's samples into their own lists, like this:
List(List(A1, A2, A3, A4), List(B1, B2, B3, B4), List(C1, C2, C3, C4), List(D1, D2, D3, D4))
How would I go about doing this in idiomatic Scala? I just started learning Scala a few hours ago, and the only non-imperative solution I've come up with is clearly nonoptimal:
def uninterleave(samples: Array[Byte], numChannels: Int, bytesPerSample: Int) = {
val dropAmount = numChannels * bytesPerSample
def extractChannel(n: Int) = {
def extrInner(in: Seq[Byte], acc: Seq[Byte]): Seq[Byte] = {
if(in == List()) acc
else extrInner(in.drop(dropAmount), in.take(bytesPerSample) ++ acc)
}
extrInner(samples.drop(n * bytesPerSample), Nil)
}
for(i <- 0 until numChannels) yield extractChannel(i)
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
但我不会
保证它的性能。我宁愿避免列表,不幸的是
grouped
产生它们。也许
仍然有很多清单。
I would do
I would not vouch for its performance though. I would rather avoid lists, unfortunately
grouped
produces them.Maybe
Still, lots of lists.
didierd 的 答案几乎是完美的,但是,唉,我认为可以稍微改进一下。他关心所有列表的创建,转置也是一个相当繁重的操作。如果您可以同时处理所有数据,那就足够了。
不过,我将使用
Stream
,并使用一些小技巧来避免转置。首先,分组是相同的,只是我将内容转换为流:
接下来,我将为您提供一个从中提取一个通道的函数:
有了这些,我们可以解码流像这样:
这将为每个通道返回单独的流而手头没有整个流。如果您需要实时处理输入,这可能很有用。这是一些输入源,用于测试它读取输入的深度以获取特定元素:
然后您可以尝试如下操作:
didierd's answer is just about perfect, but, alas, I think one can improve it a bit. He is concerned with all the list creation, and transpose is a rather heavy operation as well. If you can process all the data at the same time, it might well be good enough.
However, I'm going with
Stream
, and use a little trick to avoid transposing.First of all, the grouping is the same, only I'm turning stuff into streams:
Next, I'll give you a function to extract one channel from that:
With those, we can decode the streams like this:
This will return separate streams for each channel without having the whole stream at hand. This might be useful if you need to process the input in real time. Here's some input source to test how far into the input it reads to get at a particular element:
You can then try stuff like this: