如何获取一个列表的反向副本(在使用 .reverse 方法后链接其他方法时避免使用单独语句)?

42

这段代码运行失败:

fCamel = 'F'
bCamel = 'B'
gap = ' '

k = ['F', ' ', 'B', 'F']

def solution(formation):
    return ((formation.index(bCamel) > (len(formation) - 1 - (formation.reverse()).index(fCamel))))

solution(k)

我得到一个异常,内容为 AttributeError: 'NoneType' object has no attribute 'index'

我知道问题在于 list.reverse() 修改了列表但是返回了None。我想在翻转后的列表中使用.index方法。有没有办法避免在索引列表之前使用单独的语句来翻转列表?如何实现?


如果您要查找的元素不在列表中会发生什么?也许,如果您描述一下您正在尝试做什么,我们可以帮助您制定更好、更符合“Pythonic”的解决方案。 - GWW
我正在尝试用Python解决那个骆驼难题,以便更好地学习这门语言。基本上,这个函数应该在第一个“B”左边的所有“F”都是真实的情况下返回true。 - nakiya
只是好奇。我看到越来越多的问题没有得到赞同。对我来说,这似乎是一个有趣但简单的问题。为什么人们不多投一些问题的票呢?我经常看到回答获得了大量的投票,这意味着问题至少有潜力带来有趣的解决方案或讨论,但问题本身却没有得到任何投票。对我来说很奇怪(O_O)干杯! - Morlock
@Morlock:我也常常想到这个问题,我总是尽力给任何有趣的问题点赞。 - GWW
list.reverse不会返回列表。这是事实。你有什么问题? - S.Lott
11个回答

61

您可以使用切片来返回反转的列表:

l[::-1]

如果最后能加上"l = [...] / print(l) / print(l[::-1])"就太好了。 - Gabriel Ciubotaru
4
这是此问题的真实答案。它原地反转列表,因此您可以在列表推导式中使用它。 - user1207456

37
你可以使用 reversed(formation) 来返回 formation 的反向迭代器。当你调用 formation.reverse() 时,它会对列表进行原地翻转并返回 None。

编辑:

我现在明白你想做什么了,我认为最好使用列表推导式来完成这个任务:

def solution(formation):
    return len([k for k in formation[formation.index(bCamel)+1:] if k == fCamel]) == 0

这个代码基本上是查找第一个bCamel元素之后的所有元素,并收集值为fCamel的所有元素。如果列表长度等于0,则表示已经找到解决方案。

以下是一些示例:

>>> k = ['F','F','B','B','F']
>>> solution(k)
False
>>> k = ['F','F','B','B','B']
>>> solution(k)
True
>>> k = ['F','F','B','F','F','B','B']
>>> solution(k)
False
>>> 

4
这不适用于原始代码,因为“reversed”并不返回一个列表,而是一个迭代器(它没有“index”的方法)。 - rbp
是的,我记得了并调整了我的评论。他肯定需要稍微修改一下他的代码才能让它按照他想要的方式工作。 - GWW
我明白这一点。但是,如果它返回了反转对象(这个?或者在Python中你怎么称呼它?),那就更有意义了,对吧?还有其他的函数可以做到这一点吗?否则我又得再写几行代码了:( - nakiya
2
如果你非常想把它写成一行,你可以使用类似 list(reversed(formation)) 的方法。但是你可能来自其他编程语言,很快就会发现 Python 不喜欢仅仅为了一行代码而创建大量相似的方法 :) - rbp
GWW:一点也不;some_list [:: -1] 是反转列表的常用习语 :) - rbp
显示剩余3条评论

8

在GWW的回答基础上,如果你想让这段代码原封不动地工作,你只需要使用 list(reversed(formation))。如果你真的想使用 formation.reverse(),那么你需要创建 list 的子类:

>>> class ReversableList(list):
...     def reverse(self):
...         return list(reversed(self))
... 
>>> x = ReversableList([1,2,3])
>>> x.reverse()
[3, 2, 1]

当然,这是否可取是另一个问题。

6

list.reverse会就地反转列表。也就是说:

>>> l = [1, 2, 3]
>>> l.reverse()
>>> l
[3, 2, 1]

请参考Python文档,此类内容在其中有详细说明。您也可以尝试使用内建的 'help' 功能:

help(l.reverse) 帮助关于内建函数reverse:

reverse(...) L.reverse() -- 原地 反转


5

我刚遇到这个问题,想为那些从Javascript背景转来的Python新手澄清一些事情。

在Javascript中,a.reverse()是就地反转数组,并在调用时返回该数组。

Javascript:

var a = [2, 3 ,4]
console.log(a.reverse())
// outputs [4, 3, 2]
console.log(a)
// outputs [4, 3, 2]

在Python中,a.reverse()会原地翻转数组,但不返回该数组。这就是我感到困惑的原因。
在Python中:
a = [2, 3, 4]
a.reverse()
print(a)
# outputs [4, 3, 2]
# can't do print(a.reverse())

1
这并没有回答问题 - 它只是更清楚地解释了问题。 - Karl Knechtel

2
以下更改将生效:
NumSet={1,2,3,4,5,6,7,8,9,10}
NumList = list(NumSet)
NumList.reverse()
print(NumList)
  • 避免在初始赋值后使用赋值运算符,因为列表是可变类型。

  • 使用=运算符与方法配合使用(例如NumList = NumSet.reverse())将导致该方法用空白覆盖列表,从而有效地清除列表。这就是为什么列表变成了NoneType。 方法是函数,实际上没有自己的值,因此为空白。


1

该帖子显示了解决问题的多种方法。总结如下:

  • 使用不同的技术,给出一个反转的列表副本,以便可以在此处使用该表达式。两种主要的方法是formation[::-1]list(reversed(formation))(请参见如何反转列表?)。

类似的解决方案也存在于替换其他列表功能中,例如:

# mylist.append(1)
# mylist.index(1)
(mylist + [1]).index(1) # note that the value is wrapped in another list

# mylist.extend(anotherlist)
# mylist.index(1)
(mylist + anotherlist).index(1)

# mylist.sort()
# mylist.index(1)
sorted(mylist).index(1)

咬紧牙关,还是使用单独的语句。"简单优于复杂",好的Python风格通常避免使用类似于((formation.index(bCamel) > (len(formation) - 1 - (formation.reverse()).index(fCamel))))这样难以理解逻辑的长表达式。请记住,由于我们仍然使用了原地方法,原始的formation仍然被修改。这可能很有用,但经常会引起问题。
(请不要在真正的代码中使用此方法。)我们可以滥用条件表达式,使赋值作为副作用发生:
def solution(formation):
    return formation.index(bCamel) > (
         len(formation) - 1 - (formation.reverse() or formation).index(fCamel)
    )

这个想法是由于 formation.reverse() 会返回 None,它是 falsey的,因此 or 被强制不要短路,并且 将计算为 反转后作为副作用发生的 formation

其他表达式也可以有同样的效果,例如 [formation, formation.reverse()][0]。这个想法是编写一个包括 .reverse 调用的 表达式,但 评估为 原始列表对象。我们在这里可以任意创造性 - 但再次强调,简单比复杂好。请不要做这些事情。

请记住,这仍然会修改原始列表,可能会影响未来的计算。

重新设计逻辑以避免需要反转列表。代码尝试反转列表,搜索反转后的列表以找到第一个匹配项的索引,然后将该结果从 len(formation) - 1 中减去——这样做的总体效果是搜索最后一个匹配项的索引。列表没有这样的方法,但字符串有;而恰好我们所有的元素都是单个字符的字符串。我们可以通过用字符串表示阵型来更简单地解决问题:
def solution(formation):
    return formation.index(bCamel) > formation.rindex(fCamel)

solution('F BF')

我们也可以以不同的方式考虑这个问题:“列表的第一个bCamel之后是否存在fCamel?” 接受的答案展示了使用列表推导式来迭代“列表中第一个bCamel之后的部分”,制作那里所有fCamel的列表,并检查该列表是否非空。但我们可以更简单地完成它:
# works with either the string or list input
def solution(formation):
    return fCamel not in formation[formation.index(bCamel)+1:]

甚至有更聪明的方法来编写这个代码,例如使用迭代器的Stefan的答案。
这样的解决方案是针对代码所解决的问题具体而言的,并没有回答一般性的问题。然而,在其他情境中可能会找到类似的解决方案。

0

这并没有提供解决 F _ B F 模式问题的方案,但它解决了使用 .reverse() 时 Python 不返回列表的问题

这是我解决它的方法:

chars = ['a', '-', 'c']
chars2 = [] + chars
chars2.reverse()
totalChars = chars + chars2

totalChars返回a-cc-a,这正是我想要的,并且chars2是一个列表,而不是指向chars的指针。希望这可以帮到你。


0

这并不是特别美观,但我没有在之前的答案中找到等效的内容。如果速度或内存成本较低(列表不太长或操作没有重复执行大量次数),这相当简单直接,甚至更容易阅读。

import copy

fCamel = 'F'
bCamel = 'B'
gap = ' '

k = ['F', ' ', 'B', 'F']

def solution(formation):
    rev_formation = copy.copy(formation)
    rev_formation.reverse()
    return ((formation.index(bCamel) > (len(formation) - 1 -
            (rev_formation).index(fCamel))))

干杯


OP特别询问如何避免使用临时变量(这里是rev_formation)。 - Karl Knechtel

0

我不知道这对你是否有效,但对我来说有效:

list = [1,2,3]
print([list, list.reverse()][0])

list.reverse() 返回 None 的原因是该函数没有返回任何内容。

使用您的代码:

fCamel = 'F'
bCamel = 'B'
gap = ' '

k = ['F', ' ', 'B', 'F']

def solution(formation):
    return ((formation.index(bCamel) > (len(formation) - 1 - ([formation, formation.reverse()][0]).index(fCamel))))

print(solution(k))

希望这对你有用!
顺便说一句,老实说,我不知道为什么这个有效。我是偶然发现的。

1
它的工作原理非常容易理解:[list, list.reverse()] 在原列表上直接将其翻转,并返回一个包含翻转过的列表以及返回值 None 的列表。然后 [0] 获取第一个元素,也就是翻转后的列表。 - Karl Knechtel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接