c

codeye

V1

2022/09/26阅读:16主题:默认主题

Python list 常见用法

测试你对Python列表知识的60个问题 通过掌握列表基础知识来压制算法问题

图片来自Pexels的Andrew Neel 我最近做了很多算法题,发现自己对列表的理解并不尽如人意。

这是我写的60个列表问题的汇编,以评估我自己的知识。

我希望你会发现它和写它对我一样有用。

问题1-10。

  1. 检查一个列表是否包含一个元素 如果一个特定的元素在一个列表中,in运算符将返回True。
li = [1,2,3,'a','b','c']
'a' in li 
#=> True
  1. 如何同时在2个以上的列表上进行迭代 你可以压缩()列表,然后迭代zip对象。zip对象是一个图元的迭代器。

下面我们同时对3个列表进行迭代,并将数值插值为一个字符串。


name = ['Snowball''Chewy''Bubbles''Gruff']
animal = ['Cat''Dog''Fish''Goat']
age = [1, 2, 2, 6]
z = zip(name, animal, age)
#=> <zip at 0x111081e48>
for name,animal,age in z:
    print("%s the %s is %s" % (name, animal, age))
    
#=> Snowball the Cat is 1
#=> Chewy the Dog is 2
#=> Bubbles the Fish is 2
#=> Gruff the Goat is 6
  1. 你什么时候会使用列表和字典?

列表和字典的使用情况一般略有不同,但也有一些重叠的地方。

我得出的算法问题的一般规则是,如果你能同时使用,就使用字典,因为查找的速度更快。

列表

如果你需要存储某些东西的顺序,就使用列表。

例如:数据库记录的id,按其显示的顺序。

ids = [23,1,7,9]

虽然从 python 3.7 开始,列表和字典都是有序的,但列表允许重复的值,而字典不允许重复的键。

字典

如果你想计算某个东西的出现次数,可以使用字典。比如家里有多少只宠物。

pets = {'dogs':2, 'cats':1, 'fish':5}

。 每个键在一个字典中只能存在一次。注意,键也可以是其他不可变的数据结构,如图元。例如:

{('a',1):1, ('b',2):1}

  1. 列表是可变的吗?

是的。请注意下面的代码,在内存中与同一标识符相关的值并没有改变。

x = [1]
print(id(x),':',x) #=> 4501046920 : [1]
x.append(5)
x.extend([6,7])
print(id(x),':',x) #=> 4501046920 : [1, 5, 6, 7]
  1. 列表必须是同质的吗?

不需要。不同类型的对象可以混合在一个列表中。

a = [1,'a',1.0,[]]
#=> [1, 'a', 1.0, []]
  1. append和extend之间的区别是什么?

.append() 将一个对象添加到一个列表的末尾。

a = [1,2,3]
a.append(4)
#=> [1, 2, 3, 4]

这也意味着追加一个列表将整个列表作为一个元素添加,而不是追加它的每个值。

a.append([5,6])
#=> [1, 2, 3, 4, [5, 6]]

.extend() 将第二个列表中的每个值作为它自己的元素加入。所以用另一个列表来扩展一个列表,将它们的值结合起来。

b = [1,2,3]
b.extend([5,6])
#=> [1, 2, 3, 5, 6]
  1. python 列表是存储值还是指针?

Python 列表本身并不存储值。它们存储指向内存中其他地方的值的指针。这允许列表是可变的。

这里我们初始化值 1 和 2,然后创建一个包括值 1 和 2 的列表。

print( id(1) ) #=> 4438537632
print( id(2) ) #=> 4438537664
a = [1,2,3]
print( id(a) ) #=> 4579953480
print( id(a[0]) ) #=> 4438537632
print( id(a[1]) ) #=> 4438537664

注意到这个列表有自己的内存地址。但是列表中的1和2与我们之前定义的1和2指向内存中的同一位置。

8. del 是做什么的? del从一个列表中删除一个给定索引的项目。

这里我们将删除索引1的值。

a = ['w''x''y''z']
#=> ['w', 'x', 'y', 'z']
del a[1]
#=> ['w', 'y', 'z']

注意del并没有返回被删除的元素。

  1. removepop之间的区别是什么?

.remove()删除一个匹配对象的第一个实例。下面我们删除第一个b。

a = ['a''a''b''b''c''c']
a.remove('b')
#=> ['a', 'a', 'b', 'c', 'c']

.pop()通过索引删除一个对象。

pop和del的区别在于,pop返回被弹出的元素。这允许像堆栈一样使用一个列表。

a = ['a''a''b''b''c''c']
a.pop(4) #=> 'c'。
#=> ['a', 'a', 'b', 'b', 'c']

默认情况下, 如果没有指定索引, pop会从一个列表中删除最后一个元素.

  1. 删除列表中的重复元素

如果你不关心保持列表的顺序,那么转换为集合,再转换为列表就可以实现这个目的。

li = [3, 2, 2, 1, 1, 1].
list(set(li)) #=> [1, 2, 3]

问题11-20

  1. 找到第一个匹配元素的索引

例如,你想在一个水果的列表中找到第一个 "苹果"。 使用.index()方法。

fruit = ['pear''orange''apple''grapefruit''apple''pear']
fruit.index('apple'#=> 2
fruit.index('pear'#=> 0
  1. 从一个列表中删除所有元素

与其创建一个新的空列表,我们不如用.clear()清除现有列表中的元素。

fruit = ['pear''orange''apple']
print( fruit )     #=> 
['pear''orange''apple']

print( id(fruit) ) #=> 
4581174216

fruit.clear()
print( fruit )     #=> []
print( id(fruit) ) #=> 4581174216

或者用del

fruit = ['pear''orange''apple']
print( fruit )     #=> ['pear', 'orange', 'apple']
print( id(fruit) ) #=> 4581166792
del fruit[:]
print( fruit )     #=> []
print( id(fruit) ) #=> 4581166792
  1. 遍历一个列表中的值和它们的索引

enumerate()在作为参数传递的列表中添加一个计数器。

下面我们对列表进行迭代,并将值和索引都传到字符串插值中。

grocery_list = ['flour','cheese','carrots']
for idx,val in enumerate(grocery_list):
    print("%s: %s" % (idx, val))
    
#=> 0: flour
#=> 1: cheese
#=> 2: carrots
  1. 如何将两个列表连接起来

+运算符将串联两个列表。

one = ['a''b''c']
two = [1, 2, 3]
one + two #=> ['a', 'b', 'c', 1, 2, 3]
  1. 如何用列表理解法操作列表中的每个元素

下面我们返回一个新的列表,每个元素都加了1。

li = [0,25,50,100]。
[i+1 for i in li] 
#=> [1, 26, 51, 101]
  1. 计算一个特定对象在列表中的出现次数

count()方法返回一个特定对象的出现次数。下面我们返回字符串 "fish "在一个叫做pets的列表中的出现次数。

pets = ['dog''cat''fish''fish''cat']
pets.count('fish')
#=> 2
  1. 如何浅层复制一个列表?

.copy()可以用来浅层复制一个列表。

下面我们创建一个round1的浅层拷贝,将其分配给一个新的名字round2,然后删除sonny chiba这个字符串。

round1 = ['chuck norris''bruce lee''sonny chiba']
round2 = round1.copy()
round2.remove('sonny chiba')
print(round1) #=> ['Chuck Norris', 'Bruce Lee', 'sonny chiba']
print(round2) #=> ['Chuck Norris', 'Bruce Lee']
  1. 为什么要创建一个列表的浅层拷贝?

在前面的例子基础上,如果我们不创建一个浅层拷贝,修改round2就会修改round1。

round1 = ['chuck norris''bruce lee''sonny chiba']
round2 = round1
round2.remove('sonny chiba')
print(round1) #=> ['Chuck Norris', 'Bruce Lee']
print(round2) #=> ['Chuck Norris', 'Bruce Lee']

如果没有浅层拷贝,round1和round2只是指向内存中同一个列表的名字。这就是为什么看起来改变一个的值会改变另一个的值。

  1. 如何深度复制一个列表?

为此我们需要导入 copy 模块,然后调用 copy.deepcopy()

下面我们创建一个列表的深度拷贝,round1称为round2,更新round2的一个值,然后打印这两个值。在这种情况下,round1不受影响。

round1 = [
    ['Arnold''Sylvester''Jean Claude'],
    ['Buttercup''Bubbles''Blossom']
]
import copy
round2 = copy.deepcopy(round1)
round2[0][0] = 'Jet Lee'
print(round1)
#=> [['Arnold', 'Sylvester', 'Jean Claude'], ['Buttercup', 'Bubbles', 'Blossom']]
print(round2)
#=> [['Jet Lee', 'Sylvester', 'Jean Claude'], ['Buttercup', 'Bubbles', 'Blossom']]

上面我们可以看到,改变round2中的嵌套数组并没有更新round1。

  1. 深拷贝和浅拷贝的区别是什么? 在前面的例子基础上,创建一个浅层拷贝,然后修改它,会影响到原来的列表。
round1 = [
    ['Arnold''Sylvester''Jean Claude'],
    ['Buttercup''Bubbles''Blossom']
]
import copy
round2 = round1.copy()
round2[0][0] = 'Jet Lee'
print(round1)
#=> [['Jet Lee', 'Sylvester', 'Jean Claude'], ['Buttercup', 'Bubbles', 'Blossom']]
print(round2)
#=> [['Jet Lee', 'Sylvester', 'Jean Claude'], ['Buttercup', 'Bubbles', 'Blossom']]

为什么会发生这种情况?

创建一个浅层拷贝确实在内存中创建了一个新的对象,但是它充满了对现有对象的引用,与之前的列表相同。

创建一个深层拷贝会创建原始对象的副本并指向这些新的版本。因此,新列表完全不受旧列表变化的影响,反之亦然。

问题21-30

  1. 列表和元组之间有什么区别。

元组在创建后不能被更新。添加/删除/更新一个现有的元组需要创建一个新的元组。

列表在创建后可以被修改。

元组通常代表一个对象,如从数据库加载的记录,其中的元素是不同的数据类型。

Lists一般用于存储一个特定类型的对象的有序序列(但不一定)。

两者都是序列,允许重复的值。

  1. 返回一个列表的长度 len()可以返回一个列表的长度。
li = ['a''b''c''d''e']
len(li)
#=> 5

但是注意它计算的是顶层对象,所以一个由几个整数组成的嵌套列表只会被算作一个对象。下面,li的长度是2,而不是5。

li = [[1,2],[3,4,5]] 。
len(li)
#=> 2
  1. 列表和集合的区别是什么?

列表是有序的, 而集合不是. 这就是为什么使用set来寻找列表中的唯一值, 像

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

会改变顺序.

列表经常被用来追踪顺序,而集合则经常被用来追踪存在。

列表允许重复,但集合中的所有值根据定义是唯一的。

  1. 如何检查一个元素是否不在列表中?

为此,我们使用in运算符,但在其前面加上not。

li = [1,2,3,4] 。
5 not in li #=> True
4 not in li #=> False
  1. 用map函数将一个列表中的每个元素乘以5

map()允许在一个序列上迭代,并用另一个函数来更新每个值。 map()返回一个map对象,但我用一个列表理解来包装它,所以我们可以看到更新的值。

def multiply_5(val):
    返回 val * 5
a = [10,20,30,40,50]
[val for val in map(multiply_5, a)]。
#=> [50, 100, 150, 200, 250]
  1. 用zip函数将两个列表合并为一个图元列表

zip()将多个序列合并成一个图元的迭代器,在同一序列索引的值被合并在同一个图元中。

alphabet = ['a''b''c']
integers = [1, 2, 3]
list(zip(alphabet, integers))
  1. 在现有列表的特定索引处插入一个值 insert()方法接收一个要插入的对象和要插入的索引。
li = ['a''b''c''d''e']
li.insert(2, 'HERE')
li #=> ['a', 'b', 'here', 'c', 'd', 'e']

注意,之前在指定索引处的元素被移到了右边,而不是被覆盖。

  1. 用 reduce 函数将一个列表中的值从第一个元素中减去 reduce() 需要从 functools 中导入。

给定一个函数,reduce 遍历一个序列并在每个元素上调用该函数。在下一个元素上调用函数时,前一个元素的输出被作为参数传递。

from functools import reduce
def subtract(a,b):
    return a - b
numbers = [100,10,5,1,2,7,5]
reduce(subtract, numbers) #=> 70

上面我们从100中减去了10、5、1、2、7和5。

  1. 用filter函数从一个列表中删除负值 filter()将从一个序列中移除该函数没有返回 True 的任何元素。

下面我们删除小于 0 的元素。

def remove_negatives(x):
    return True if x >= 0 else False
    
a = [-10, 27, 1000, -1, 0, -30]
[x for x in filter(remove_negatives, a)] 
#=> [27, 1000, 0]
  1. 将一个列表转换成一个字典,其中列表元素是键 为此我们可以使用字典的理解力。
li = ['The''quick''brown'
      'fox''was''quick']
d = {k:1 for k in li}
#=> {'The': 1, 'quick': 1, 
        'brown': 1, 'fox': 1, 'was': 1}

问题31-40

  1. 用lambda函数修改一个现有的列表 让我们把之前写的map函数,用lambda把它变成一个单行代码。
a = [10,20,30,40,50]
list(map(lambda val:val*5, a))
#=> [50, 100, 150, 200, 250]

我可以把它作为一个map对象,直到我需要对它进行迭代,但我转换为一个列表,以显示里面的元素。

  1. 删除列表中特定索引后的元素

使用slice语法,我们可以返回一个新的列表,其中只有特定索引之前的元素。

li = [1,2,3,4,5,6,7,8,9,10,
      11,12,13,14,15,16,17,
      18,19,10]
li[:10]
#=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
  1. 删除列表中特定索引之前的元素

slice 语法也可以返回一个新的列表,其中包含指定索引之后的值。

li = [1,2,3,4,5,6,7,8,9,10,
      11,12,13,14,15,16,17,
      18,19,10] 。
li[15:]
#=> [16, 17, 18, 19, 10]
  1. 删除一个列表中2个索引之间的元素

或者在两个索引之间。

li = [1,2,3,4,5,6,7,8,9,10,
      11,12,13,14,15,16,17,
      18,19,10] 。
li[12:17]
#=> [13, 14, 15, 16, 17]
  1. 返回2个索引之间的列表中的每一个第二元素

或者在一个特定的间隔内,在指数之前/之后/之间。

这里我们使用slice语法返回指数10和16之间的每一个第2个值。

li = [1,2,3,4,5,6,7,8,9,10,
      11,12,13,14,15,16,17,
      18,19,10] 。
li[10:16:2]
#=> [11, 13, 15]
  1. 对一个整数列表按升序排序 sort() 方法将一个列表突变为升序排列。
li = [10,1,9,2,8,3,7,4,6,5] 。
li.sort()
li #=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]
  1. 对一个整数列表按降序排序

通过添加参数reverse=True,也可以用sort()进行降序排序。

li = [10,1,9,2,8,3,7,4,6,5] 。
li.sort(reverse=True)
li #=> [10, 9, 8, 7, 6, 5, 4, 3, 2, 1] 
  1. 用列表理解法从列表中过滤偶数值

你可以在列表理解中添加条件逻辑,以过滤掉遵循特定模式的值。

这里我们过滤掉能被 2 整除的值。

li = [1,2,3,4,5,6,7,8,9,10]。
[i for i in li if i % 2 != 0]。
#=> [1, 3, 5, 7, 9]
  1. 计算一个列表中每个值的出现次数

一种选择是迭代一个列表并将计数添加到一个字典中。但是最简单的方法是从 collections 中导入 Counter 类,然后将列表传递给它。

from collections import Counter
li = ['blue''pink''green'
      'green''yellow''pink''orange']
Counter(li)
#=> Counter({'blue': 1, 'pink': 2, 
            'green': 2, 'yellow': 1, 'orange': 1})
  1. 从一个列表中的每个嵌套列表中获取第一个元素

列表理解很适合在一个由其他对象组成的列表上进行迭代,并从每个嵌套对象中抓取一个元素。

li = [[1,2,3], [4,5,6], 
      [7,8,9], [10,11,12],
      [13,14,15]]
[i[0]for i in li]
#=> [1, 4, 7, 10, 13]

问题41-50

  1. 对一个列表来说,插入、查找和删除的时间复杂度是多少?

插入是O(n)复杂度,如果一个元素被插入到开头,所有其他元素必须向右移动。

通过索引查找是O(1)。但是按值查找是O(n),因为元素需要被迭代直到找到值。

删除是O(n)。如果一个元素在开始时被删除,所有其他的元素必须向左移动。

  1. 将一个列表中的元素合并成一个字符串。 这可以用 join() 函数来完成。
li = ['The','quick','brown'
      'fox''jumped''over'
      'the''lazy''dog']
' '.join(li)
#=> 
'The quick brown fox jumped over the lazy dog'

  1. 列表乘以一个整数有什么影响?

将一个列表乘以一个整数被称为多重连接,其影响与将一个列表与它本身连接n次是一样的。

下面我们将一个列表乘以5。

['a','b'] * 5
#=> 
['a''b''a''b''a''b''a''b']

这与以下情况相同

['a','b'] + ['a','b'] + ['a','b'] + ['a','b]] 
#=> ['
a', 'b', 'a', 'b', 'a', 'b', 'a', 'b']
  1. 使用 "any "函数,如果列表中的任何值都能被2整除,则返回True

我们可以将any()与列表理解结合起来,如果返回的列表中的任何值评估为 True,则返回 True。

下面的第一个列表理解返回 True,因为该列表中有一个 2,是可以被 2 整除的。


li1 = [1,2,3]。
li2 = [1,3]
any(i % 2 == 0 for i in li1) #=> True
any(i % 2 == 0 for i in li2) #=> False

  1. 使用 "all "函数,如果一个列表中的所有值都是负数,则返回 "真 与any()函数类似, all()也可以与列表理解一起使用, 只在返回的列表中的所有值都是True时返回True。
li1 = [2,3,4].
li2 = [2,4]
all(i % 2 == 0 for i in li1) #=> False
all(i % 2 == 0 for i in li2) #=> True
  1. 你能对一个含有 "None "的列表进行排序吗?

你不能对含有 "无 "的列表进行排序,因为比较运算符(sort()使用的)不能将一个整数与 "无 "进行比较。

li = [10,1,9,2,8,3,7,4,6,None] 。
li.sort()
li #=> TypeError: 'NoneType'和'int'的实例之间不支持'<'
  1. 列表构造函数会从一个现有的列表中创建什么样的副本?

list 构造函数为传入的 list 创建一个浅层拷贝。也就是说,这比使用 .copy() 更不符合 pythonic。

li1 = ['a','b'] 。
li2 = list(li1)
li2.append('c')
print(li1) #=> ['a', 'b']
print(li2) #=> ['a', 'b', 'c']
  1. 反转一个列表的顺序

可以用reverse()方法将一个列表突变为反向顺序。

li = [1,2,3,4,5,6,7,8,9,10] 。
li.reverse()
li #=> [10, 9, 8, 7, 6, 5, 4, 3, 2, 1] 

注意,这是在保持原对象的id()地址不变,改变顺序,而不是返回一个新对象。

  1. reverse和reversed之间的区别是什么?

reverse()将列表原地反转,改变原变量列表的顺序!小心 reversed()返回列表的一个反向顺序的可迭代对象。


li = [1,2,3,4,5,6,7,8,9,10] 。
list(reversed(li))
#=> [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
  1. sort和sorted之间的区别是什么?

sort()在原地修改列表。 sorted()返回一个相反顺序的新列表。

li = [10,1,9,2,8,3,7,4,6,5]
li.sort()
li #=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
li = [10,1,9,2,8,3,7,4,6,5] 。
sorted(li) #=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] 

问题51-60

  1. 返回一个列表中的最小值 min()函数返回一个列表中的最小值。
li = [10,1,9,2,8,3,7,4,6,5] 
min(li)
#=> 1
  1. 返回列表中的最大值

max()函数返回一个列表中的最大值。

li = [10,1,9,2,8,3,7,4,6,5] 
max(li)
#=> 10

  1. 返回一个列表中的数值之和

sum()函数返回一个列表中所有数值的总和。

li = [10,1,9,2,8,3,7,4,6,5] 
sum(li)
#=> 55
  1. 将一个列表作为一个堆栈

你可以使用append()pop()来把一个列表当作一个堆栈。堆栈的功能是按后进先出(last in first out)

stack = []
stack.append('Jess')
stack.append('Todd')
stack.append('Yuan')
print(stack) #=> ['Jess', 'Todd', ' Yuan']
print(stack.pop()) #=> Yuan
print(stack) #=> ['Jess', 'Todd']

堆栈的一个好处是,可以在O(1)时间内添加和删除元素,因为列表不需要被迭代。

  1. 寻找2个列表的交集

我们可以通过利用带有set()来实现这个目的。

li1 = [1,2,3] 
li2 = [2,3,4]
set(li1) & set(li2)
#=> {2, 3}

  1. 找出一个集合和另一个集合的区别

我们不能-减去列表,但是我们可以减去集合。

li1 = [1,2,3] 。
li2 = [2,3,4]。
set(li1) - set(li2)
#=> {1}
set(li2) - set(li1)
#=> {4}
  1. 用列表理解法平坦一个列表

与 Ruby 不同,Python3 没有一个明确的 flatten 函数。但是我们可以使用 list comprehension 来平坦一个列表的列表。

li = [[1,2,3],[4,5,6]] 
[i for x in li for i in x]
#=> [1, 2, 3, 4, 5, 6]

  1. 生成一个2个值之间的每个整数的列表

我们可以在2个值之间创建一个范围,然后将其转换为一个列表。

list(range(5,10))
#=> [5, 6, 7, 8, 9]

  1. 将 2 个列表合并成一个字典

使用 zip()list() 构造函数,我们可以将 2 个列表合并成一个字典,其中一个列表成为键,另一个列表成为值。

name = ['Snowball''Chewy''Bubbles''Gruff']
animal = ['Cat''Dog''Fish''Goat']
dict(zip(name, animal))

  1. 使用slice语法反转列表的顺序

虽然我们可以用 reverse()reversed() 来反转一个列表,但也可以用 slice 语法来完成。

这将通过从头到尾遍历列表返回一个新的列表。


li = ['a','b',3,4] 。
li[::-1]
#=> [4, 3, 'b', 'a']

结论 在完成这些工作后,我觉得自己更有能力解决算法问题,而不必再猜测具体的列表方法。

消除不断的搜索可以为更高层次的思考释放能量,比如让一个函数做它应该做的事,并降低函数的复杂性。

再次,我希望你也觉得这很有用。

分类:

后端

标签:

后端

作者介绍

c
codeye
V1