我正在尝试获取列表中每个元素之间的拍频,(获取每个元素与每个其他元素之间的差的绝对值。
如果列表是
[a,b,c]
我要生成
[a,b,c,| a-b |,| a-c |,| b-c |]
但是我现在正在做的事情(简单地遍历列表中的每个元素然后再次进行遍历)对于我正在处理的元素数量来说确实很慢,是否还有其他我可以使用的数据结构或方法使此操作更快?
下面的代码是我现在正在做的。我是python的新手,没有从基础知识中学到许多数据结构,所以很抱歉,如果解决方案实际上是我从未想到过的真正明显的东西!
我与处理器进行了交谈,他提到了晶格,是纯粹的数学概念,还是在代码中有一些可以使用的实现方式,或者甚至对我的案例有用吗?
这是我当前正在运行的代码。它获取频率和幅度的列表,其中频率在[n]处的幅度为幅值[n]。一旦找到唯一的拍频,它将被添加到列表中,其幅度是输入频率的幅度的平均值,因此,如果在a = 1时为440hz,在a = 2时为110hz,则拍频将为abs (440-110)在a =((1 + 2)/ 2)。
def beatSet(frequencies, amplitudes, tol) :
for index_x, x in enumerate(frequencies) :
for index_y, y in enumerate(frequencies[index_x+1:]) :
beat_freq = abs(x - y)
if search(frequencies, beat_freq, tol) : #returns true if beat_freq isn't a duplicate, within a tolerance
frequencies.append(beat_freq)
amplitudes.append((amplitudes[index_y] + amplitudes[index_x])/2)
和搜索功能如下:
def search(list_in, search_term, tolerance) :
for i in list_in :
if abs(search_term - i) <= tolerance :
return False
return True
通常,一个输入列表将有大约10-50个元素,但是输出可能会变得很大,例如[440,441]会生成一个输出列表,如果没有公差,该列表将非常大,因此公差在某种程度上是输出列表大小的限制因素。通常,当输入列表中两个频率的差刚好在容差之上时,将生成最大的输出列表。
对不起,我希望我已经对所有内容进行了充分的解释!
答案 0 :(得分:0)
您的方法遇到的一个问题是它可以适应原始方法
您可以对频率进行排序,然后使用bisect
在排序列表中进行搜索:
import bisect
import itertools
def beat_set(frequencies, amplitudes, tolerance):
sorted_frequencies = sorted(zip(frequencies, amplitudes))
results = {}
for (
(index_x, (freq_x, ampl_x)),
(index_y, (freq_y, ampl_y)),
) in itertools.combinations(enumerate(sorted_frequencies), 2):
beat_frequency = abs(freq_x - freq_y)
if not search_bisect(sorted_frequencies, beat_frequency, tolerance):
# beat_frequency already in frequencies
continue
beat_amplitude = (ampl_x + ampl_y) / 2
bisect.insort_left(sorted_frequencies, (beat_frequency, beat_amplitude))
return sorted_frequencies
(beat_set(frequencies, amplitudes, tolerance))
def search_bisect(sorted_frequencies, beat_frequency, tolerance):
insert_index = bisect.bisect_left(sorted_frequencies, (beat_frequency,))
if insert_index == 0:
return abs(sorted_frequencies[0][0] - beat_frequency) > tolerance
return all(
abs(sorted_frequencies[insert_index - i][0] - beat_frequency)
> tolerance
for i in (0, 1)
)
在找到的每个节拍上更新频率列表,但仅比较原始频率。在OP的解决方案中,第二个for循环使用了更新的频率。
frequencies = 440, 441 amplitudes = 2, 1 tolerance = 0.1 beat_set(frequencies, amplitudes, tolerance)
[(1, 1.5), (440, 2), (441, 1)]
-
def search_until_convergence(
frequencies, amplitudes, tolerance, max_iterations=100
):
result_new = beat_set(frequencies, amplitudes, tolerance)
result_old = None
for i in itertools.count():
if i >= max_iterations:
raise ValueError(f"No Convergence after {i} iterations")
frequencies_new, amplitudes_new = zip(*result_new)
if result_old == result_new:
return {
"frequencies": frequencies_new,
"amplitudes": amplitudes_new,
"iterations": i,
}
result_old = result_new
result_new = beat_set(frequencies_new, amplitudes_new, tolerance)