我希望编写一个数据结构来表示一些遗传数据。这个数据可以表示为大小n
的列表,其中每个条目也有一个“遗传位置”,它是0到1之间的实数。为了使术语清晰,我将在列表中调用该位置id
和基因位置gpos
。我实现这个的方式是一个带
class Coords(object):
def __init__(self, *args, **kwargs):
self.f = list(*args, **kwargs)
self.r = dict()
for i,e in enumerate(self.f):
self.r[e] = i
def __setitem__(self,x,y):
self.f.__setitem__(x,y)
self.r.__setitem__(y,x)
def __getitem__(self,x):
return self.f.__getitem__(x)
def __len__(self):
return self.f.__len__()
现在,我有两个问题。第一个是self.r的浮点数是浮点数,这显然是一个坏主意。我想将它们转换为字符串(具有固定数字的数字),但有更好的想法吗?我遇到的另一个问题是我想通过gpos
实现访问条目,所以如果我想访问gpos
0.2和0.4之间的所有内容,我希望能够做到使用
import numpy as np
Coords(np.arange(1,0,-.1))
c.r[0.2:0.4]
有一种简单的方法可以定义吗?我正在考虑使用二进制搜索找到正确的id
开始和结束位置,然后使用这些ID访问self.f
,但有没有办法实现上述语法?
答案 0 :(得分:5)
使用切片索引对象时,Python会使用您提供的输入创建一个slice
对象。例如,如果您执行c[0.2:0.4]
,则传递给c.__getitem__
的参数将为slice(0.2, 0.4)
。因此,您可以在__getitem__
方法中使用此代码:
def __getitem__(self, x):
if isinstance(x, slice):
start = x.start
stop = x.stop
step = x.step
# Do whatever you want to do to define your return
...
如果你想在Coords
对象上但不在self.r
字典中使用这个花哨的索引,我认为最简单的方法是创建一个FancyIndexDict
,它是一个子类。 dict
,修改其__getitem__
方法,然后将self.r
设为FancyIndexDict
,而不是dict
。
答案 1 :(得分:3)
如果您知道您的gpos
值将(或可以)始终按排序顺序存储,那么我肯定建议使用二进制搜索来完成此任务。您可以利用searchsorted的数组语法和numpy
内置实现:
>>> gpos_vals = np.linspace(0, 1, 11)
>>> gpos_vals
array([ 0. , 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1. ])
>>> lo, hi = gpos_vals.searchsorted([0.22, 0.52])
>>> lo, hi
(3, 6)
>>> gpos_vals[lo:hi]
array([ 0.3, 0.4, 0.5])
我认为这很好地避免了你指出的关于为字典键使用浮点数的问题,这可能会有问题。
您还可以将此答案与Jaime合并,并创建一个在自定义__getitem__
内查找切片的类,然后将切片参数传递给searchsorted
,如我的代码段所示:
class GeneticPositions(object):
def __init__(self, gpos_values):
self.gpos_values = np.asarray(gpos_values)
def __getitem__(self, x):
if isinstance(x, slice):
lo, hi = self.gpos_values.searchsorted(
[x.start or 0, x.stop or 1])
return self.gpos_values[lo:hi]
return self.gpos_values[x]