在列表之间重复列表元素,直到达到一定长度

时间:2015-12-23 09:08:05

标签: python numpy

我有一个以数字开头的列表,并且已经接近结尾了

[1,2,3, nan, nan, nan, nan]

我希望在我的列表的整个长度上展开可用的数字,直到所有的数据都被覆盖。

我们的列表中有些人,我们从第一个数字开始:[1, 1, 2, 3, nan, nan, nan]列表中是否还有南方?是的:[1,1,2,2,3, nan, nan] ... [1,1,2,2,3,3,nan] ...如果所有的人都被覆盖,那么列表就会像

一样

[1,1,1,2,2,3,3]

实现这一目标的最佳方式是什么?

编辑:

nan是numpy.nan,可以用None替换

5 个答案:

答案 0 :(得分:4)

这是另一个解决每个列表元素必须重复多少次的解决方案

import itertools as it
l = [1, 2, 3, 'nan', 'nan', 'nan', 'nan']

off = l.index('nan') # offset of the first 'nan' element
subl = l[:off] # to avoid slicing more than once

rem = len(l) % off # remainder
rep = len(l) // off # min repetitions

rep_el = (rep+1 if p < rem else rep for p,el in enumerate(subl))
newl = it.chain(*(it.repeat(el,r) for el,r in zip(subl, rep_el)))

print(list(newl))

产生

[1, 1, 1, 2, 2, 3, 3]

rem是列表中元素总数的除法的余数,以及没有&#39; NaN&#39;

的元素数量

rep是所有元素的最小重复次数

rep_el是一个包含每个列表元素必须具有的重复的生成器。如果元素的位置小于余数,则意味着它的重复应该增加1。

newl是新组建的列表。它是通过将重复每个元素所产生的重复连接起来按照上面计算的正确次数来构建的。

答案 1 :(得分:2)

你可以这样做(如果我理解你的问题):

my_list = [1, 2, 3, None, None, None, None]
result = [x for x in my_list if x is not None]
result.extend([result[i%len(result)] for i in xrange(len(my_list)-len(result))])
result.sort()

如果您必须保存原始订单,只需将最后一个字符串替换为:

result.sort(key=lambda x: my_list.index(x))

答案 2 :(得分:2)

为提高效率,numpy解决方案:

import numpy as np
a=np.array([1,2,3,np.nan,np.nan,np.nan,np.nan]) # an example
n=len(a)
p=n-np.isnan(a).sum() # count of valids assuming nan's at the end.
repeats=n//p
m=n-repeats*p # number of overfilled.
q=m*(repeats+1) #border
a[q:]=a[m:p].repeat(repeats) #the end
a[:q]=a[:m].repeat(repeats+1) #the beginning

结果:

array([ 1.,  1.,  1.,  2.,  2.,  3.,  3.])

答案 3 :(得分:2)

迭代解决方案

这是一个迭代解决方案,试图匹配问题中的逻辑:

x = [1,2,3,None,None,None,None,None]  # replace nan with None

def onestep(cur,y,base):
    # one step of the iteration
    if cur is not None:
        y.append(cur)
        base.append(cur)
    else:
        y.append(base[0])  # append is simplest, for now
        base = base[1:]+[base[0]]  # rotate
    return base

y=[]
base=[]
for cur in x:
    base = onestep(cur,y,base)
    # print(base,y)
print(y)

产生:

[1, 2, 3, 1, 2, 3, 1, 2]

我试着跟踪base索引,这是我接下来要插入的基础元素。但事实证明,只需旋转base就可以了,并且总是使用第一个元素。

我开始使用j索引,我逐步完成了x,但后来意识到我并不需要它来引用x[j]。我可以使用for cur in x:

迭代解决方案 - 第二版

让我们对其进行优化,以便按所需顺序收集值。为此,我需要跟踪插入点。但事实证明这很困难。所以我改用了以前用过的想法(见下文) - 收集子列表。

def onestep1(cur,y,i):
    # initial and extend sublists
    if cur is not None:
        y.append([cur])
    else:
        if i>len(y)-1:
            i = 0
        y[i].append(y[i][0])
        i += 1
    return i

y=[]
i = 0
for cur in x:
    i = onestep1(cur,y,i)
print(y, i)
制造

([[1, 1, 1], [2, 2, 2], [3, 3]], 2)

可以使用chain展平:

print(list(itertools.chain(*y)))
制造

[1, 1, 1, 2, 2, 2, 3, 3]

在这种情况下,我仍然需要跟踪i索引,指出哪个子列表可以递增。

chain的替代方案是双重理解:

[i for j in y for i in j]

全球重复

另一种方法是退出迭代细节,并查看大图。

从列表开始;让我们用nan替换None(一个numpy float),这是一个纯Python值。但它几乎可以是任何截然不同的填充物。值:

In [188]: x=[1,2,3,None,None,None,None,None]

从哪里开始?

In [190]: idx = x.index(None)
In [191]: idx
Out[191]: 3

我们想要重复的基本值是什么?

In [192]: base = x[:idx]
In [193]: base
Out[193]: [1, 2, 3]

实际上,我们希望根据需要重复base的每个值,以填充x的长度。从这个角度来看,它并不是一个真正的替代问题。它是如何将n个项目列表扩展为m项目列表。

在此示例中,我们希望重复3个值cnt次:

In [194]: cnt=[3,3,2]

numpy有一个很好的功能,可以应用cntnp.repeat

In [195]: np.repeat(base, cnt)
Out[195]: array([1, 1, 1, 2, 2, 2, 3, 3])

坚持使用列表我们可以做到:

In [196]: [[i]*j for i,j in zip(base,cnt)]
Out[196]: [[1, 1, 1], [2, 2, 2], [3, 3]]

但这是一个嵌套列表。展平嵌套列表的一种不错的惯用方法是使用itertools.chain。这是相当&#39; pythonic&#39;使用标准库提供的工具。熟悉itertools

是一种很好的做法
In [197]: list(itertools.chain(*[[i]*j for i,j in zip(base, cnt)]))
Out[197]: [1, 1, 1, 2, 2, 2, 3, 3]

另一种应用cnt的方法是双重理解(替换列表*和chain

[i for i,c in zip(base, cnt) for _ in range(c)]

我可以使用与cnt(或onestep)中相同的逻辑来计算onestep1列表,除了累积计数值而不是子列表。

或者正如其他答案所示,我们可以从base的长度和总长度推断,使用整数除法和模数来计算应该有多少计数n,以及有多少n-1

数学上问题是:

Integers, m, n, such that:
8 = (3-m)*n + m*(n-1)
8 = 3*n -m*n + m*n - m = 3*n - m
n = (8//3) + 1 (= 3); m = 3*n - 8 (= 1)
cnt = [n]*(m-1) + [n-1]*(m) (=[3]*2 + [2]*1 = [3,3,2])

Pynchia's表达式做同样的事情:

rep_el = (rep+1 if p < rem else rep for p,el in enumerate(subl))

我不会考虑其中任何更多&#39; pythonic&#39;比其他人。它们是不同的策略,但都可以用很好的Python风格编写。

答案 4 :(得分:1)

r = '123'
i = 0
j = 0
while 'nan' in list_a:
  if i = len(r):
    i = 0
  if(list_a[j] == 'nan'):
    list_a[j] = r[i]
    i += 1
  j += 1

我认为这应该解决它。