大多数毕达哥拉斯式的方法将列表扩展到一定长度?(复制)

时间:2021-10-03 22:54:23

This question already has an answer here:

这个问题已经有了答案:

My goal is to take a list of unknown number of elements and extend/slice it to exactly n elements, padding lists that are too short with 0 and slicing lists that are too long.

我的目标是获取一个元素数量未知的列表,并将它扩展/切片到n个元素,填充太短的列表,以及分割太长的列表。

For example

例如

n = 10
foo = [1,2,3,4]
print some_func(foo,n) 

should return [1,2,3,4,0,0,0,0,0,0], and

应该返回(1、2、3、4、0,0,0,0,0,0),然后呢

n = 10
foo = [1,2,3,4,5,6,7,8,9,10,11,12]
print some_func(foo,n)

should return [1,2,3,4,5,6,7,8,9,10]

应该返回[1,2,3,4,5,6,7,8,9,10)


Right now I'm doing this:

现在我正在做:

def some_function(l, n):
    l.extend([0] * n)
    l = l[:n]
    return l

But that seems inefficient. Is there a more pythonic way of doing this?

但这似乎效率低下。有没有一种更符合python的方法呢?


EDIT: point of clarification, I am not trying to modify the original array, I am returning a new array that can be a shallow copy.

编辑:澄清一下,我不是要修改原始数组,而是返回一个可以是浅拷贝的新数组。

6 个解决方案

#1


2  

The only potentially "more Pythonic" way to do this is pretty much the way you have it, but skip over the extra variable allocation and just return the result directly. You could also definitely make it more Pythonic by conforming to PEP8 with your function and variable names.

唯一可能的“更多的python化”方式是您拥有它的方式,但是跳过额外的变量分配,直接返回结果。通过使用函数名和变量名与PEP8相一致,您也可以使它更符合python语言。

Besides that, you can improve your efficiency by adding only as many zeroes as you need, rather than building a too-long list and then trimming it.

除此之外,你可以通过只增加你所需要的0来提高你的效率,而不是建立一个太长的列表然后对它进行调整。

def pad_or_truncate(some_list, target_len):
    return some_list[:target_len] + [0]*(target_len - len(some_list))

Breaking it down, there are two cases represented here (discounting the trivial case where the input is exactly the right length already). Either the list is too long, or the list is too short.

把它分解,这里有两种情况(折现输入的长度正好是正确的)。要么列表太长,要么列表太短。

If the list is too long, we just slice it. some_list[:target_len] takes care of that. Because the slice operation is friendly, this won't blow up if the target length is beyond the actual length of the list.

如果列表太长,我们就把它切片。some_list[:target_len]负责这个。因为切片操作是友好的,如果目标长度超出了列表的实际长度,这不会被放大。

If the list is too short, we pad it with zeroes. I chose to do this by multiplying a list literal1, but you can use a list comprehension the exact same way2 if that's more your cup of tea. Just determine how many zeroes to add (either zero, if the list isn't too short, or target_len - len(some_list)), and concatenate a list composed of that many zeroes. Done and done!

如果列表太短,我们用0填充它。我选择将列表按字面量相乘,但如果你更喜欢列表,你也可以用同样的方法来理解列表。只需确定要添加多少个0(如果列表不太短,可以是0,或者是target_len - len - len(some_list))),并将由这些0组成的列表连接起来。完成了,完成了!

If you want to make it an in-place operation (as your original example appears to be trying but failing to achieve; see @chepner's comment), you would just change return <...> to some_list[:] = <...>.

如果你想让它成为一个就地操作(就像你最初的例子一样,它似乎在尝试,但却没有实现;查看@chepner的评论),您只需更改return <…>到some_list[:] = <…>。


1Some brief timeit results indicated that literal multiplication is a bit quicker than the double-iteration implied by a list comprehension.

一些简短的时间结果表明,文字乘法比列表理解所暗示的双迭代要快一些。

2For posterity, the list comprehension version would look something like:

对于后代来说,列表理解版本应该是这样的:

return some_list[:target_len] + [0 for _ in range(target_len - len(some_list))]

#2


4  

It is quite inefficient to build the list bigger than you need it (particularly if n gets large); instead, only add the padding you need. Also, it is Python convention to return None if a function changes its argument(s) in-place:

建立一个比你需要的更大的列表是非常低效的(尤其是当n变大时);相反,只需添加所需的填充。此外,如果一个函数在适当的地方更改了参数,则Python约定不返回任何参数:

def some_func(l, n, pad=0):
    if len(l) >= n:
        del l[n:]
    else:
        l.extend([pad] * (n - len(l)))

Example:

例子:

>>> l = [1, 2, 3, 4, 5]
>>> some_func(l, 3)
>>> l
[1, 2, 3]
>>> some_func(l, 5)
>>> l
[1, 2, 3, 0, 0]

Alternatively, return a new list:

或者,返回一个新列表:

def some_func(l, n, pad=0):
    if len(l) >= n:
        return l[:n]
    return l + ([pad] * (n - len(l)))

#3


1  

How about islice-ing the concatenation of the original list with a padding generator?

如何使用填充生成器连接原始列表?

from itertools import islice, repeat
def fit_to_size(l, n):
    return list(islice(
        ( x
          for itr in (l, repeat(0))
          for x in itr ),
        n))

You might prefer this slightly more explicit implementation:

您可能更喜欢这个稍微显式的实现:

def fit_to_size(l, n):
    def gen():
        yield from l
        while True: yield 0
    return list(islice(gen(), n))

#4


1  

Why not use conditional logic?

为什么不使用条件逻辑呢?

def pad_or_slice(L, n):
    if len(L) < n:
        return L + ([0] * (n - len(L)))
    else:
        return L[:n]

This way you're only doing one of the two, not both, at the cost of checking the length of the list, which shouldn't be too costly.

这样,你只需要检查列表的长度,而不是同时检查两个列表中的一个,这应该不会太贵。

#5


0  

It's not significantly more efficient, but I'd do l = (l + [0] * (n - len(l)))[:n]. So your some_function would look like this

它的效率并不是很高,但我要用l = (l + [0] * (n - len(l)))[:n]所以some_function应该是这样的

def some_function(list, n):
    return (list + [0] * (n - len(list)))[:n]

#6


0  

In order to properly modify the original list, you'll need to delete a trailing slice from the object.

为了正确地修改原始列表,您需要从对象中删除一个尾随片。

def some_function(l, n):
    l.extend([0] * n)
    del l[n:]

#1


2  

The only potentially "more Pythonic" way to do this is pretty much the way you have it, but skip over the extra variable allocation and just return the result directly. You could also definitely make it more Pythonic by conforming to PEP8 with your function and variable names.

唯一可能的“更多的python化”方式是您拥有它的方式,但是跳过额外的变量分配,直接返回结果。通过使用函数名和变量名与PEP8相一致,您也可以使它更符合python语言。

Besides that, you can improve your efficiency by adding only as many zeroes as you need, rather than building a too-long list and then trimming it.

除此之外,你可以通过只增加你所需要的0来提高你的效率,而不是建立一个太长的列表然后对它进行调整。

def pad_or_truncate(some_list, target_len):
    return some_list[:target_len] + [0]*(target_len - len(some_list))

Breaking it down, there are two cases represented here (discounting the trivial case where the input is exactly the right length already). Either the list is too long, or the list is too short.

把它分解,这里有两种情况(折现输入的长度正好是正确的)。要么列表太长,要么列表太短。

If the list is too long, we just slice it. some_list[:target_len] takes care of that. Because the slice operation is friendly, this won't blow up if the target length is beyond the actual length of the list.

如果列表太长,我们就把它切片。some_list[:target_len]负责这个。因为切片操作是友好的,如果目标长度超出了列表的实际长度,这不会被放大。

If the list is too short, we pad it with zeroes. I chose to do this by multiplying a list literal1, but you can use a list comprehension the exact same way2 if that's more your cup of tea. Just determine how many zeroes to add (either zero, if the list isn't too short, or target_len - len(some_list)), and concatenate a list composed of that many zeroes. Done and done!

如果列表太短,我们用0填充它。我选择将列表按字面量相乘,但如果你更喜欢列表,你也可以用同样的方法来理解列表。只需确定要添加多少个0(如果列表不太短,可以是0,或者是target_len - len - len(some_list))),并将由这些0组成的列表连接起来。完成了,完成了!

If you want to make it an in-place operation (as your original example appears to be trying but failing to achieve; see @chepner's comment), you would just change return <...> to some_list[:] = <...>.

如果你想让它成为一个就地操作(就像你最初的例子一样,它似乎在尝试,但却没有实现;查看@chepner的评论),您只需更改return <…>到some_list[:] = <…>。


1Some brief timeit results indicated that literal multiplication is a bit quicker than the double-iteration implied by a list comprehension.

一些简短的时间结果表明,文字乘法比列表理解所暗示的双迭代要快一些。

2For posterity, the list comprehension version would look something like:

对于后代来说,列表理解版本应该是这样的:

return some_list[:target_len] + [0 for _ in range(target_len - len(some_list))]

#2


4  

It is quite inefficient to build the list bigger than you need it (particularly if n gets large); instead, only add the padding you need. Also, it is Python convention to return None if a function changes its argument(s) in-place:

建立一个比你需要的更大的列表是非常低效的(尤其是当n变大时);相反,只需添加所需的填充。此外,如果一个函数在适当的地方更改了参数,则Python约定不返回任何参数:

def some_func(l, n, pad=0):
    if len(l) >= n:
        del l[n:]
    else:
        l.extend([pad] * (n - len(l)))

Example:

例子:

>>> l = [1, 2, 3, 4, 5]
>>> some_func(l, 3)
>>> l
[1, 2, 3]
>>> some_func(l, 5)
>>> l
[1, 2, 3, 0, 0]

Alternatively, return a new list:

或者,返回一个新列表:

def some_func(l, n, pad=0):
    if len(l) >= n:
        return l[:n]
    return l + ([pad] * (n - len(l)))

#3


1  

How about islice-ing the concatenation of the original list with a padding generator?

如何使用填充生成器连接原始列表?

from itertools import islice, repeat
def fit_to_size(l, n):
    return list(islice(
        ( x
          for itr in (l, repeat(0))
          for x in itr ),
        n))

You might prefer this slightly more explicit implementation:

您可能更喜欢这个稍微显式的实现:

def fit_to_size(l, n):
    def gen():
        yield from l
        while True: yield 0
    return list(islice(gen(), n))

#4


1  

Why not use conditional logic?

为什么不使用条件逻辑呢?

def pad_or_slice(L, n):
    if len(L) < n:
        return L + ([0] * (n - len(L)))
    else:
        return L[:n]

This way you're only doing one of the two, not both, at the cost of checking the length of the list, which shouldn't be too costly.

这样,你只需要检查列表的长度,而不是同时检查两个列表中的一个,这应该不会太贵。

#5


0  

It's not significantly more efficient, but I'd do l = (l + [0] * (n - len(l)))[:n]. So your some_function would look like this

它的效率并不是很高,但我要用l = (l + [0] * (n - len(l)))[:n]所以some_function应该是这样的

def some_function(list, n):
    return (list + [0] * (n - len(list)))[:n]

#6


0  

In order to properly modify the original list, you'll need to delete a trailing slice from the object.

为了正确地修改原始列表,您需要从对象中删除一个尾随片。

def some_function(l, n):
    l.extend([0] * n)
    del l[n:]