两个列表的同类混合

时间:2015-09-01 18:06:22

标签: python

我想以最同质的方式在不同长度的python中混合两个列表。

a = [1,2,3]
b = ['a', 'b', 'c', 'd', 'e', 'f']

a和b的合并列表应该导致

c = ['a', 'b', 1, 'c', 'd', 2, 'e', 'f', 3]

是否存在合并这两个列表的pythonic方法,如果len(b)/ len(a)不是整数,它也可以工作吗?

5 个答案:

答案 0 :(得分:2)

这是解释同质混合的一种方法:假设两个列表分别具有长度m和n(分别)。将第一个列表的元素放在实线的子区间[0,1]上,均匀间隔,每个元素之间的间隙为1 / m。因此我们可以将这些元素放置在0 / m,1 / m,2 / m,...(m-1)/ m的位置。但是还有一些回旋余地:我们也可能将元素放置在x / m,(x + 1)/ m,(x + 2)/ m,...的位置,对于范围[0]中的任何x ,1)。对第二个列表的元素执行相同的操作,将它们放置在彼此相距1 / n的距离处,以便所有元素再次包含在[0,1]中。现在,要获得两个列表的同类混合,请按照它们沿实线显示的顺序读取所有元素(来自两个列表)。如果展示位置使得第一个和第二个列表中的元素在一个或多个点处完全重合,则每次发生时优先考虑第一个列表(比如说)。

你可以相对容易地编写这个想法,经过一些简化后,你会得到一些相当简短和优雅的东西。这是一个生成函数,它生成混合列表的连续元素:

def mix_lists(l1, l2):
    """ Mix two lists evenly, generating the elements of the mixed list. """
    m, n = len(l1), len(l2)
    for i in range(m + n):
        q, r = divmod(i * n, m + n)
        yield l1[i - q] if r < m else l2[q]

这对应于我们将第一个列表的元素尽可能地放在[0,1]内,即0 / m,1 / m,......的情况。第二个列表的元素靠近最右边的位置(所以第一个元素接近1 / n,第二个元素接近2 / n等)因此,在我们拥有的自由中,第一个列表的元素往往更早出现而不是第二次。

以下是一个例子,其中一个列表的长度是另一个列表的倍数:

>>> list(mix_lists('abcdef', [1, 2, 3]))
['a', 'b', 1, 'c', 'd', 2, 'e', 'f', 3]

以下几个例子并非如此:

>>> list(mix_lists('abcdefgh', range(12)))
['a', 0, 'b', 1, 2, 'c', 3, 'd', 4, 5, 'e', 6, 'f', 7, 8, 'g', 9, 'h', 10, 11]
>>> list(mix_lists('abcdefg', [1, 2, 3, 4]))
['a', 'b', 1, 'c', 'd', 2, 'e', 'f', 3, 'g', 4]

现在进行一些变化,您可以在divmod调用中添加偏移:该偏移应严格在0 <= offset < m + n范围内。调整偏移量以移动一个或另一个列表的元素(但是移位受到限制,使得所有元素仍位于区间[0,1)内)。通过改变偏移量,我们可以获得所有可能的&#34;均匀混合&#34;图案。

def mix_lists(l1, l2, offset=0):
    """ Mix two lists evenly, generating the elements of the mixed list. """
    m, n = len(l1), len(l2)
    for i in range(m + n):
        q, r = divmod(i * n + offset, m + n)
        yield l1[i - q] if r < m else l2[q]

以下是偏移量变化时混合差异的一些例子。

>>> list(mix_lists('abcdefg', [1, 2, 3, 4], offset=0))
['a', 'b', 1, 'c', 'd', 2, 'e', 'f', 3, 'g', 4]
>>> list(mix_lists('abcdefg', [1, 2, 3, 4], offset=2))
['a', 'b', 1, 'c', 2, 'd', 'e', 3, 'f', 'g', 4]
>>> list(mix_lists('abcdefg', [1, 2, 3, 4], offset=5))
['a', 1, 'b', 'c', 2, 'd', 3, 'e', 'f', 4, 'g']
>>> list(mix_lists('abcdefg', [1, 2, 3, 4], offset=9))
[1, 'a', 'b', 2, 'c', 3, 'd', 'e', 4, 'f', 'g']
>>> mix_lists('abcdefg', [1, 2, 3, 4], offset=10)
[1, 'a', 2, 'b', 'c', 3, 'd', 'e', 4, 'f', 'g']

选择m + n - 1的最大偏移量会导致第二个列表优先于第一个列表,而选择约(m + n)/ 2的偏移量将意味着我们从较长列表中的元素开始,在一个列表恰好比另一个列表长一个元素的情况下,效果特别好:

>>> list(mix_lists('abcd', [1, 2, 3]))
['a', 'b', 1, 'c', 2, 'd', 3]
>>> list(mix_lists('abcd', [1, 2, 3], offset=3))
['a', 1, 'b', 2, 'c', 3, 'd']
>>> list(mix_lists('abcd', [1, 2, 3], offset=6))
[1, 'a', 2, 'b', 3, 'c', 'd']

答案 1 :(得分:0)

这是一种方法。我找到第一个列表到第二个列表的长度的比率a:b,用最低的术语表示,然后我通过交替第二个列表的b个元素块后跟{{a来构建列表。 1}}第一个元素:

import fractions
def mixLists(xs,ys):
    m = len(xs)
    n = len(ys)
    d = fractions.gcd(m,n)
    s = m//d
    t = n//d
    xslices = (xs[i:i+s] for i in range(0,m,s))
    yslices = (ys[i:i+t] for i in range(0,n,t))
    mixed = []
    for x,y in zip(xslices,yslices):
        mixed.extend(y)
        mixed.extend(x)
    return mixed

典型输出:

>>> a = [1,2,3]
>>> b = ['a','b','c','d','e','f']
>>> mixLists(a,b)
['a', 'b', 1, 'c', 'd', 2, 'e', 'f', 3]
>>> a = [1,2,3,4]
>>> mixLists(a,b)
['a', 'b', 'c', 1, 2, 'd', 'e', 'f', 3, 4]

如果长度之间有一个很好的比率a:b,则此函数将返回一个列表,其中大小为a+b的连续切片将具有从两个列表中的每一个中提取的代表量。但是 - 在长度相对较长的情况下,结果不是很均匀:

>>> a = [1,2,3,4,5]
>>> mixLists(a,b)
['a', 'b', 'c', 'd', 'e', 'f', 1, 2, 3, 4, 5]

在这种情况下,你需要更仔细地考虑你想要的东西。

答案 2 :(得分:0)

def homogenized(bigList,smallList):
    ratio=len(bigList)/len(smallList) #integer division, needs to change for python 3
    smallList.reverse()
    counter=0
    out=[]
    for element in bigList:
        out.append(element)
        counter=counter+1
        if counter==ratio:
            counter=0
            try:
                out.append(smallList.pop())
            except IndexError:
                pass
    return out

print homogenized(['a', 'b', 'c', 'd', 'e'], [1,2,3])
print homogenized(['a', 'b', 'c', 'd', 'e', 'f'], [1,2,3])
print homogenized(['a', 'b', 'c', 'd', 'e', 'f', 'g'], [1,2,3])



>>> 
['a', 1, 'b', 2, 'c', 3, 'd', 'e']
['a', 'b', 1, 'c', 'd', 2, 'e', 'f', 3]
['a', 'b', 1, 'c', 'd', 2, 'e', 'f', 3, 'g']

大名单必须先行。将其包裹在检查功能强大的订购功能中。

答案 3 :(得分:0)

我在这里基于@Mark Dickinson的答案。 我发现生成器比性能较低的版本更难理解:

def mix_lists(l1, l2):
    """ Mix two lists evenly, generating the elements of the mixed list. """
    _l1 = [(i / len(l1), v) for i, v in enumerate(l1)]
    _l2 = [(i / len(l2), v) for i, v in enumerate(l2)]
    return [v for i, v in sorted(_l1 + _l2)]

我不会在没有任何解释的情况下将任何一个版本引入代码库。 马克的好东西,完全让我开心。

答案 4 :(得分:-1)

如果len(b)/ len(a)不是整数,则甚至无法正确分发列表。

这个问题更像是算法相关而不是编码部分。要组合这两个列表,首先需要弄清楚模式。如果a中有x个元素,b中有nx个元素,那么列表的长度为x + nx。它意味着对于a中的每个元素,将有来自b的n个元素。

所以,首先你需要找到这个1 - df[::-1].cummin()[::-1] / df.cummax(),这可以通过找出列表长度的比例来完成。然后在空列表中,在a中添加模式1元素中的元素,从b中添加n个元素,依此类推,直到你拥有df = web.DataReader(stocks, 'yahoo', start, end)['Adj Close'] df_pullback = 1 - df[::-1].cummin()[::-1] / df.cummax() df_pullback.plot() 中的所有元素。

这是一个小型的Python程序。您可以根据自己的喜好对其进行相应修改。

n

输出

c
相关问题