Python切片列表中的第一个和最后一个元素


70

有没有办法只分割列表中的第一项和最后一项?

例如; 如果这是我的清单:

>>> some_list
['1', 'B', '3', 'D', '5', 'F']

这样做(显然[0,-1]是无效的语法):

>>> first_item, last_item = some_list[0,-1]
>>> print first_item
'1'
>>> print last_item
'F'

我尝试过的一些方法:

In [3]: some_list[::-1]
Out[3]: ['F', '5', 'D', '3', 'B', '1']

In [4]: some_list[-1:1:-1]
Out[4]: ['F', '5', 'D', '3']

In [5]: some_list[0:-1:-1]
Out[5]: []
...

6
哈哈在2秒的时间内回答了3个相同的答案,一个是您的。经典。
Esthete 2012年

3
有什么不好的first, last = some_list[0], some_list[-1]
马修·亚当斯

@MatthewAdams因为我将其拆分在同一行中,所以必须花时间将其拆分两次:x, y = a.split("-")[0], a.split("-")[-1]
chown 2012年

3
FWIW,我会some_list[0::len(some_list)-1]在代码审查中拒绝。太聪明了一半。
DSM

2
@chown:但是,如果您将步骤的解决方案设置为len-1,则无论如何都必须再次拆分两次以获取长度!
的Martijn Pieters的

Answers:


96

单程:

some_list[::len(some_list)-1]

更好的方法(不使用切片,但更易于阅读):

[some_list[0], some_list[-1]]

20
第二种形式是更具有可读性。显式总比隐式好。
的Martijn Pieters的

4
因此,“可能是更好的方法”。我没有首先提到的唯一原因是因为问题明确要求“切片”,而第二种形式从技术上讲不是切片...
mgilson 2012年

3
对OP进行愚蠢的教育永远不会太晚。:-P
Martijn Pieters

1
如果some_list中只有一项,则切片形式失败,并显示“ ValueError:切片步长不能为零”
rickfoosusa 2015年

1
@rickfoosusa-好吧...我想这取决于预期的输出。您说对了,因为它没有给您提供2个项目(对于许多应用程序),因此可能被认为是错误...“更好”的方式给您两次相同的项目,根据情况同样可能差强人意在我认为的应用程序上……
mgilson 2015年

19

只是以为我会展示如何使用numpy的精美索引来做到这一点:

>>> import numpy
>>> some_list = ['1', 'B', '3', 'D', '5', 'F']
>>> numpy.array(some_list)[[0,-1]]
array(['1', 'F'], 
      dtype='|S1')

请注意,它还支持任意索引位置, [::len(some_list)-1]方法不适用于:

>>> numpy.array(some_list)[[0,2,-1]]
array(['1', '3', 'F'], 
      dtype='|S1')

正如DSM所指出的,您可以使用itemgetter进行类似的操作:

>>> import operator
>>> operator.itemgetter(0, 2, -1)(some_list)
('1', '3', 'F')

numpy通常会让我微笑!
jterrace 2012年

4
你可以得到的这个变体使用工作itemgetternumpyitemgetter(0, -1)(some_list)
DSM

17

Python 3中唯一的答案(不使用切片或扔掉的剩余部分list,但可能不够好反正)是使用拆包概括获得firstlast从中间分开:

first, *_, last = some_list

选择_“全部”作为论点“其余部分”是任意的;它们将以名称存储_通常用作“我不在乎的东西”的代名词。

与许多其他解决方案不同,该解决方案将确保序列中至少包含两个元素;如果只有一个(sofirst并且last将是相同的),它将引发一个异常(ValueError)。


3
我很惊讶这没有得到更多的支持。到目前为止,这是最优雅的解决方案,并且避免多次引用该列表。非常适合诸如“打开文件-获取第一行-分割它-获取第一个元素和最后一个元素(这就是我来到这里的东西)之类的东西。”
nicolaum

@nicolaum:鉴于它是在其他答案发布五年后发布的,所以我并不感到特别惊讶。如果有的话,我很惊讶它的上升如此之高,因为人们只有在寻找此问题并滚动到接受的答案时才看到它,它通常不会出现在任何人的首页上。考虑到它实际上并没有丢弃中间元素,而是被迫构造一个临时元素list(其他答案避免了这一点,以不保证至少两个元素为代价),这并不是一个完美的解决方案。
ShadowRanger

它也是O(N),而许多其他解决方案是O(1)。无论物质或不依赖于应用:)很多。
mgilson

@mgilson:是的,这是使用任意迭代器(包括迭代器)的必要结果;你不能不走到尽头。:-)
ShadowRanger


7

看来有人在回答错误的问题。您说您想做:

>>> first_item, last_item = some_list[0,-1]
>>> print first_item
'1'
>>> print last_item
'F'

即,您要提取第一个和最后一个元素到单独的变量中。

在这种情况下,Matthew Adams,pemistahl和katrielalex的答案是有效的。这只是一个复合任务:

first_item, last_item = some_list[0], some_list[-1]

但是稍后您会感到复杂:“我将它分割在同一行中,这将需要花费时间将其分割两次:”

x, y = a.split("-")[0], a.split("-")[-1]

因此,为了避免两次split()调用,您必须仅对列表进行操作,该列表是由一次拆分产生的。

在这种情况下,尝试在一行中执行太多操作会损害清晰度和简洁性。使用变量保存拆分结果:

lst = a.split("-")
first_item, last_item = lst[0], lst[-1]

其他答复回答了“如何获取一个由列表的第一和最后一个元素组成的新列表”的问题。根据您对问题的仔细阅读,它们可能是受您的标题启发的,其中提到切片实际上是您所不希望的。

AFAIK是通过列表的第0个元素和最后一个元素获取新列表的3种方法:

>>> s = 'Python ver. 3.4'
>>> a = s.split()
>>> a
['Python', 'ver.', '3.4']

>>> [ a[0], a[-1] ]        # mentioned above
['Python', '3.4']

>>> a[::len(a)-1]          # also mentioned above
['Python', '3.4']

>>> [ a[e] for e in (0,-1) ] # list comprehension, nobody mentioned?
['Python', '3.4']

# Or, if you insist on doing it in one line:
>>> [ s.split()[e] for e in (0,-1) ]
['Python', '3.4']

列表理解方法的优点在于,元组中的索引集可以是任意的,并且可以通过编程方式生成。


只是一个FYI,列表理解方法的优势是“任意和以编程方式生成的”索引,这是通过使用的解决方案来operator.itemgetter共享的;itemgetter在构造它时需要花费任意数量的内容来查找,并tuple在集合上调用结果时将它们作为一个整体检索。通常,它的运行速度比listcomp快,尤其是如果itemgetterprecomp是预先构造和重用的,尽管它的缺点是,如果只请求一项,则不会汇总结果。
ShadowRanger



4

其实,我只是想出了:

In [20]: some_list[::len(some_list) - 1]
Out[20]: ['1', 'F']

3

这不是“切片”,而是一种不使用显式索引的通用解决方案,并且适用于所讨论序列是匿名的情况(因此您可以在同一行上创建和“切片”,而无需创建两次并索引两次): operator.itemgetter

import operator

# Done once and reused
first_and_last = operator.itemgetter(0, -1)

...

first, last = first_and_last(some_list)

您可以将其内联为(from operator import itemgetter为简洁起见,在使用后):

first, last = itemgetter(0, -1)(some_list)

但是如果您将大量重复使用getter,则可以通过提前创建一次来保存重新创建它的工作(并给它一个有用的,自我记录的名称)。

因此,对于您的特定用例,您可以替换:

x, y = a.split("-")[0], a.split("-")[-1]

与:

x, y = itemgetter(0, -1)(a.split("-"))

并且split只有一次,而没有list以永久名称存储完整的len检查或双索引等。

请注意,itemgetter对于多个项目,返回tuple,而不是list,因此,如果您不只是将其解压缩为特定名称,并且需要true list,则必须将调用包装在list构造函数中。


1
那是一个可爱的而且非常快!
达里亚(Daria)

3

您可以使用类似

y[::max(1, len(y)-1)]

如果您真的想使用切片。这样做的优点是它不会产生索引错误,并且也可以使用长度为1或0的列表。


3

另一个python3解决方案使用带“ *”字符的元组拆包:

first, *_, last = range(1, 10)

2

更一般的情况:从列表的每个末端返回N点

答案适用于特定的第一个和最后一个,但是有些答案,例如我自己,可能正在寻找一种可以应用于更一般情况的解决方案,在这种情况下,您可以从列表的任一侧返回前N个点(例如排序列表,只想要5个最高或最低),我想出了以下解决方案:

In [1]
def GetWings(inlist,winglen):
    if len(inlist)<=winglen*2:
        outlist=inlist
    else:
        outlist=list(inlist[:winglen])
        outlist.extend(list(inlist[-winglen:]))
    return outlist

以及返回列表1-10的底部和顶部3个数字的示例:

In [2]
GetWings([1,2,3,4,5,6,7,8,9,10],3)

#Out[2]
#[1, 2, 3, 8, 9, 10]

0

一种有趣的新方法,可以“匿名”处理一个匿名split事件,这样您就不会将它拆分两次,但是在一行中完成所有工作都是使用walrus运算符:=,将其作为表达式执行赋值,同时允许两种操作:

first, last = (split_str := a.split("-"))[0], split_str[-1]

和:

first, last = (split_str := a.split("-"))[::len(split_str)-1]

请注意,在两种情况下,它基本上等同于一行执行:

split_str = a.split("-")

然后执行以下一项操作:

first, last = split_str[0], split_str[-1]
first, last = split_str[::len(split_str)-1]

包括split_str持续超出其使用和访问范围的事实。从技术上讲,它只是满足单行代码的要求,同时相当难看。我绝对不建议在解压缩itemgetter解决方案中使用它,即使必须使用一行代码(排除显式索引或切片命名变量并且必须两次引用所述命名变量的非海象版本)。


-1

这些都很有趣,但是如果您有版本号并且不知道字符串中任何一个段的大小,并且想要删除最后一个段,该怎么办。像20.0.1.300之类的东西,我想以20.0.1结尾,最后没有300。到目前为止,我有:

str('20.0.1.300'.split('.')[:3])

它以列表形式返回:

['20', '0', '1']

如何将其恢复为由句点分隔的单个字符串

20.0.1

我猜到现在您已经弄明白了,但这是使用Python的不错的列表索引功能的问题:'.'.join('20.0.1.300'.split('.')[:-1])-x向后索引。
开普勒

-1

利用打包/拆包运算符将列表的中间打包为单个变量:

>>> l = ['1', 'B', '3', 'D', '5', 'F']
>>> first, *middle, last = l
>>> first
'1'
>>> middle
['B', '3', 'D', '5']
>>> last
'F'
>>> 

或者,如果您想丢弃中间部分:

>>> l = ['1', 'B', '3', 'D', '5', 'F']
>>> first, *_, last = l
>>> first
'1'
>>> last
'F'
>>> 

-3
def recall(x): 
    num1 = x[-4:]
    num2 = x[::-1]
    num3 = num2[-4:]
    num4 = [num3, num1]
    return num4

现在,只需在函数外部创建一个变量,然后调用该函数即可:

avg = recall("idreesjaneqand") 
print(avg)

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.