检测距离 k 处相等元素的有效函数
Efficient function to detect equal elements at distance k
我正在寻找一个有效的函数来查找列表中距离 k 处的相等元素。
输入示例:
v=['a','c','d','e','a','c','e','e','e','d']
k=4
期望的输出:
['a', 'c', 'e']
原因:
'a'同时在位置0和4 [4-0=k],'c'同时在位置1和5 [5-1=k],'e'都在位置3和 7 [7-3=k]
如果可能的话,我正在寻找比使用 for 循环逐个元素循环更有效的方法。也就是说,我正在寻找比以下更好的东西:
def dist_k(k, v):
v_len = len(v)
out = []
for i in range(0,v_len,1):
if i+k < v_len:
if v[i] == v[i+k]:
out.append(v[i])
print(out)
编辑
我找到了一种更快的聪明方法,不需要 np.roll
,并且不会将数组视为循环数组:
>>> import numpy as np
>>> v = ['a','c','d','e','a','c','e','e','e','d']
>>> v_np = np.array(v)
>>> k = 4
>>> v_init = v_np[:-k]
>>> v_init[v_init == v_np[k:]]
array(['a', 'c', 'e'])
我的想法是存储数组的开头,但没有最后 k
个元素(我不需要,因为它们后面的元素少于 k
个)。我存储数组,因为我需要它两次。
>>> v_init = v_np[:-k]
>>> v_init
array(['a', 'c', 'd', 'e', 'a', 'c'])
然后我使用没有前 k
个元素的数组的第二部分:
>>> v_np[k:]
array(['a', 'c', 'e', 'e', 'e', 'd'])
然后我可以比较两个数组:
>>> v_init == v_np[k:]
array([ True, True, False, True, False, False])
最后我可以从 v_init
中获取对应于索引的元素(不是从 v
中获取,因为数组的长度不匹配):
>>> v_init[v_init == v_np[k:]]
array(['a', 'c', 'e'])
表演
因为它使用 numpy(它使用 C 进行计算),所以这种方法对于大数组会更快。但是,由于转换为 numpy 数组,对于小列表,它可能会更慢(甚至不确定,请尝试解决您的问题):
def list_comprehension(v, k):
return [v[i] for i in range(len(v)-k) if v[i] == v[i+k]]
def using_numpy(v, k):
v_np = np.array(v)
v_init = v[:-k]
return v_init[v_init == v[k:]]
>>> from timeit import timeit
>>> v = np.random.rand(100000).tolist() # I consider that the input is a simple list
>>> timeit(lambda: list_comprehension(v,k), number=1000)
7.875344538999343
>>> timeit(lambda: using_numpy(v,k), number=1000)
3.646597085000394
原始答案,用于圆形数组
import numpy as np
v = np.array(['a','c','d','e','a','c','e','e','e','d'])
k = 4
v[v == np.roll(v,-k)]
基本上 np.roll
将数组移动 k
个元素,然后我只需将初始数组与移动后的数组进行比较,并保留它们相等的元素:
>>> np.roll(v, -k)
array(['a', 'c', 'e', 'e', 'e', 'd', 'a', 'c', 'd', 'e'])
>>> v == np.roll(v,-k)
array([ True, True, False, True, False, False, False, False, False,
False])
>>> v[v == np.roll(v,-k)]
array(['a', 'c', 'e'])
请注意,此方法会将数组视为循环数组,即它会将数组的第一个值和最后一个值视为相邻的:
>>> v=np.array(['a','c','d','e','a','c','e','e','e','d', 'a'])
>>> v[v == np.roll(v,-k)]
array(['a', 'c', 'e', 'd'])
您可以试试下面的代码:
v=['a','c','d','e','a','c','e','e','e','d']
k=4
result = [v[i] for i in range(len(v)-k) if v[i] == v[i+k] ]
我不知道这是否比其他建议更有效,但这是另一种选择:
v = ['a', 'c', 'd', 'e', 'a', 'c', 'e', 'e', 'e', 'd']
k = 4
print([e for e, f in zip(v, v[k:]) if e == f])
输出:
['a', 'c', 'e']
我正在寻找一个有效的函数来查找列表中距离 k 处的相等元素。
输入示例:
v=['a','c','d','e','a','c','e','e','e','d']
k=4
期望的输出:
['a', 'c', 'e']
原因: 'a'同时在位置0和4 [4-0=k],'c'同时在位置1和5 [5-1=k],'e'都在位置3和 7 [7-3=k]
如果可能的话,我正在寻找比使用 for 循环逐个元素循环更有效的方法。也就是说,我正在寻找比以下更好的东西:
def dist_k(k, v):
v_len = len(v)
out = []
for i in range(0,v_len,1):
if i+k < v_len:
if v[i] == v[i+k]:
out.append(v[i])
print(out)
编辑
我找到了一种更快的聪明方法,不需要 np.roll
,并且不会将数组视为循环数组:
>>> import numpy as np
>>> v = ['a','c','d','e','a','c','e','e','e','d']
>>> v_np = np.array(v)
>>> k = 4
>>> v_init = v_np[:-k]
>>> v_init[v_init == v_np[k:]]
array(['a', 'c', 'e'])
我的想法是存储数组的开头,但没有最后 k
个元素(我不需要,因为它们后面的元素少于 k
个)。我存储数组,因为我需要它两次。
>>> v_init = v_np[:-k]
>>> v_init
array(['a', 'c', 'd', 'e', 'a', 'c'])
然后我使用没有前 k
个元素的数组的第二部分:
>>> v_np[k:]
array(['a', 'c', 'e', 'e', 'e', 'd'])
然后我可以比较两个数组:
>>> v_init == v_np[k:]
array([ True, True, False, True, False, False])
最后我可以从 v_init
中获取对应于索引的元素(不是从 v
中获取,因为数组的长度不匹配):
>>> v_init[v_init == v_np[k:]]
array(['a', 'c', 'e'])
表演 因为它使用 numpy(它使用 C 进行计算),所以这种方法对于大数组会更快。但是,由于转换为 numpy 数组,对于小列表,它可能会更慢(甚至不确定,请尝试解决您的问题):
def list_comprehension(v, k):
return [v[i] for i in range(len(v)-k) if v[i] == v[i+k]]
def using_numpy(v, k):
v_np = np.array(v)
v_init = v[:-k]
return v_init[v_init == v[k:]]
>>> from timeit import timeit
>>> v = np.random.rand(100000).tolist() # I consider that the input is a simple list
>>> timeit(lambda: list_comprehension(v,k), number=1000)
7.875344538999343
>>> timeit(lambda: using_numpy(v,k), number=1000)
3.646597085000394
原始答案,用于圆形数组
import numpy as np
v = np.array(['a','c','d','e','a','c','e','e','e','d'])
k = 4
v[v == np.roll(v,-k)]
基本上 np.roll
将数组移动 k
个元素,然后我只需将初始数组与移动后的数组进行比较,并保留它们相等的元素:
>>> np.roll(v, -k)
array(['a', 'c', 'e', 'e', 'e', 'd', 'a', 'c', 'd', 'e'])
>>> v == np.roll(v,-k)
array([ True, True, False, True, False, False, False, False, False,
False])
>>> v[v == np.roll(v,-k)]
array(['a', 'c', 'e'])
请注意,此方法会将数组视为循环数组,即它会将数组的第一个值和最后一个值视为相邻的:
>>> v=np.array(['a','c','d','e','a','c','e','e','e','d', 'a'])
>>> v[v == np.roll(v,-k)]
array(['a', 'c', 'e', 'd'])
您可以试试下面的代码:
v=['a','c','d','e','a','c','e','e','e','d']
k=4
result = [v[i] for i in range(len(v)-k) if v[i] == v[i+k] ]
我不知道这是否比其他建议更有效,但这是另一种选择:
v = ['a', 'c', 'd', 'e', 'a', 'c', 'e', 'e', 'e', 'd']
k = 4
print([e for e, f in zip(v, v[k:]) if e == f])
输出:
['a', 'c', 'e']