View Categories

Python 教程 10 — 列表

13 min read

本章介绍Python中最有用的内置类型之一:列表(list)。你还将进一步学习关于对象的知识 以及同一个对象拥有多个名称时会发生什么。

1.列表是一个序列 #

与字符串类似,列表 是由多个值组成的序列。在字符串中,每个值都是字符; 在列表中,值可以是任何数据类型。列表中的值称为 元素(element) ,有时也被称为 项(item) 。

创建新列表的方法有多种;最简单的方法是用方括号( [ 和 ] )将元素包括起来:

[10, 20, 30, 40]
['crunchy frog', 'ram bladder', 'lark vomit']

第一个例子是包含4个整数的列表。第二个是一个包含3个字符串的列表。 一个列表中的元素不需要是相同的数据类型。下面的列表包含一个字符串、一个浮点数、一个整数和另一个列表:

['spam', 2.0, 5, [10, 20]]

一个列表在另一个列表中,称为**嵌套(nested)列表**。

一个不包含元素的列表被称为空列表;你可以用空的方括号 [] 创建一个空列表。

正如你想的那样,你可以将列表的值赋给变量:

>>> cheeses = ['Cheddar', 'Edam', 'Gouda']
>>> numbers = [42, 123]
>>> empty = []
>>> print(cheeses, numbers, empty)
['Cheddar', 'Edam', 'Gouda'] [42, 123] []

2.列表是可变的 #

访问列表中元素的语法,与访问字符串中字符的语法相同,都是通过方括号运算符实现的。 括号中的表达式指定了元素的索引。记住,索引从0开始:

>>> cheeses[0]
'Cheddar'

和字符串不同的是,列表是可变的。当括号运算符出现在赋值语句的左边时,它就指向了列表中将被赋值的元素。

>>> numbers = [42, 123]
>>> numbers[1] = 5
>>> numbers
[42, 5]

numbers中索引为1的元素,原来是123,现在变成了5。

图10-1:状态图 是 cheeses 、 nubmers 和 empty 的状态图。

图10-1:状态图

图10-1:状态图

列表用外部标有”list”的盒子表示,盒子内部是列表的元素。 cheeses 指向一个有3个元素的列表,3个元素的下标分别是0、1、2。numbers 包含两个元素; 状态图显示第二个元素原来是123,被重新赋值为5。 empty 对应一个没有元素的列表。

列表下标的工作原理和字符串下标相同:

  • 任何整数表达式都可以用作下标。
  • 如果你试图读或写一个不存在的元素,你将会得到一个索引错误(IndexError).
  • 如果下标是负数,它将从列表的末端开始访问列表。

in运算符在列表中同样可以使用。

>>> cheeses = ['Cheddar', 'Edam', 'Gouda']
>>> 'Edam' in cheeses
True
>>> 'Brie' in cheeses
False

3.遍历列表 #

最常用的遍历列表的方式是使用for循环。语法和字符串遍历类似:

for cheese in cheeses:
    print(cheese)

如果你只需要读取列表中的元素,这种方法已经足够。然而,如果你想要写入或者更新列表中的元素,你需要通过下标访问。一种常用的方法是结合内置函数 range 和 len :

for i in range(len(numbers)):
    numbers[i] = numbers[i] * 2

这个循环将遍历列表并更新每个元素。len 返回列表中的元素个数。range 返回一个包含从0到n−1n−1下标的列表,其中nn是列表的长度。 每次循环中,i 得到下一个元素的下标。循环主体中的赋值语句使用 i 读取该元素的旧值,并赋予其一个新值。

对一个空列表执行for循环时,将不会执行循环的主体:

for x in []:
    print('This never happens.')

尽管一个列表可以包含另一个列表,嵌套的列表本身还是被看作一个单个元素。 下面这个列表的长度是4:

['spam', 1, ['Brie', 'Roquefort', 'Pol le Veq'], [1, 2, 3]]

4.列表操作 #

+运算符拼接多个列表:

>>> a = [1, 2, 3]
>>> b = [4, 5, 6]
>>> c = a + b
>>> c
[1, 2, 3, 4, 5, 6]

运算符 * 以给定次数的重复一个列表:

>>> [0] * 4
[0, 0, 0, 0]
>>> [1, 2, 3] * 3
[1, 2, 3, 1, 2, 3, 1, 2, 3]

第一个例子重复4次。第二个例子重复了那个列表3次。

5.列表切片 #

切片(slice)运算符同样适用于对列表:

>>> t = ['a', 'b', 'c', 'd', 'e', 'f']
>>> t[1:3]
['b', 'c']
>>> t[:4]
['a', 'b', 'c', 'd']
>>> t[3:]
['d', 'e', 'f']

如果你省略第一个索引,切片将从列表头开始。如果你省略第二个索引,切片将会到列表尾结束。 所以如果你两者都省略,切片就是整个列表的一个拷贝。

>>> t[:]
['a', 'b', 'c', 'd', 'e', 'f']

由于列表是可变的,通常在修改列表之前,对列表进行拷贝是很有用的。

切片运算符放在赋值语句的左边时,可以一次更新多个元素:

>>> t = ['a', 'b', 'c', 'd', 'e', 'f']
>>> t[1:3] = ['x', 'y']
>>> t
['a', 'x', 'y', 'd', 'e', 'f']

6.列表方法 #

Python为列表提供了一些方法. 例如, append 添加一个新元素到列表的末端:

>>> t = ['a', 'b', 'c']
>>> t.append('d')
>>> t
['a', 'b', 'c', 'd']

extend将接受一个列表作为参数,并将其其中的所有元素添加至目标列表中:

>>> t1 = ['a', 'b', 'c']
>>> t2 = ['d', 'e']
>>> t1.extend(t2)
>>> t1
['a', 'b', 'c', 'd', 'e']

这个例子中 t2 没有改动。

sort将列表中的元素从小到大进行排序:

>>> t = ['d', 'c', 'e', 'b', 'a']
>>> t.sort()
>>> t
['a', 'b', 'c', 'd', 'e']

大部分的列表方法都是无返回值的;它们对列表进行修改,然后返回None。 如果你意外的写了 t.sort() ,你将会对结果感到失望的。

7.映射、筛选和归并 #

你可以这样使用循环,对列表中所有元素求和:

def add_all(t):
    total = 0
    for x in t:
        total += x
    return total

total被初始化为 0。每次循环时, x 从列表中获取一个元素。 运算符 += 提供了一个快捷的更新变量的方法。这个 增量赋值语句(augmented assignment statement)

total += x

等价于

total = total + x

当循环执行时,total 将累计元素的和;一个这样的变量有时被称为 累加器(accumulator) 。

把一个列表中的元素加起来是一个很常用的操作, 所以Python将其设置为一个内建内置函数 sum :

>>> t = [1, 2, 3]
>>> sum(t)
6

一个像这样的将一系列的元素合并成一个单一值的操作有时称为 归并(reduce) 。

有时,你在构建一个列表时还需要遍历另一个列表。 例如,下面的函数接受一个字符串列表作为参数,返回包含大写字符的新列表:

def capitalize_all(t):
    res = []
    for s in t:
        res.append(s.capitalize())
    return res

res被初始化为一个空列表;每次循环时,我们添加下一个元素。 所以 res 是另一种形式的累加器。

类似 capitalize_all 这样的操作有时被称为 映射(map) ,因为它“映射”一个函数(在本例中是方法 capitalize )到序列中的每个元素上。

另一个常见的操作是从列表中选择一些元素,并返回一个子列表。例如,下面的函数读取一个字符串列表,并返回一个仅包含大写字符串的列表:

def only_upper(t):
    res = []
    for s in t:
        if s.isupper():
            res.append(s)
    return res

isupper是一个字符串方法,如果字符串仅含有大写字母,则返回 True 。

类似 only_upper 这样的操作被称为 筛选(filter) ,因为它选中某些元素,然后剔除剩余的元素。

大部分常用列表操作可以用映射、筛选和归并这个组合表示。

8.删除元素 #

有多种方法可以从列表中删除一个元素。如果你知道元素的下标,你可以使用 pop :

>>> t = ['a', 'b', 'c']
>>> x = t.pop(1)
>>> t
['a', 'c']
>>> x
'b'

pop修改列表,并返回被移除的元素。如果你不提供下标,它将移除并返回最后一个元素。

如果你不需要被移除的元素,可以使用 del 运算符:

>>> t = ['a', 'b', 'c']
>>> del t[1]
>>> t
['a', 'c']

如果你知道要删除的值(但是不知道其下标),你可以使用 remove :

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

remove的返回值是None.

要移除多个元素,你可以结合切片索引使用 del :

>>> t = ['a', 'b', 'c', 'd', 'e', 'f']
>>> del t[1:5]
>>> t
['a', 'f']

同样的,切片选择到第二个下标(不包含第二个下标)处的所有元素。

9.列表和字符串 #

一个字符串是多个字符组成的序列,一个列表是多个值组成的序列。但是一个由字符组成的列表不同于字符串。可以使用 list 将一个字符串转换为字符的列表:

>>> s = 'spam'
>>> t = list(s)
>>> t
['s', 'p', 'a', 'm']

由于 list 是内置函数的名称,你应避免将它用作变量名。我同样避免使用 l ,因为它看起来很像1。这就是为什么我用了 t 。

list函数将字符串分割成单独的字符。如果你想将一个字符串分割成一些单词,你可以使用 split 方法:

>>> s = 'pining for the fjords'
>>> t = s.split()
>>> t
['pining', 'for', 'the', 'fjords']

可以提高一个叫做 分隔符(delimiter) 的可选参数,指定什么字符作为单词之间的分界线。下面的例子使用连字符作为分隔符:

>>> s = 'spam-spam-spam'
>>> delimiter = '-'
>>> t = s.split(delimiter)
>>> t
['spam', 'spam', 'spam']

join的功能和 split 相反。它将一个字符串列表的元素拼接起来。join 是一个字符串方法,所以你需要在一个分隔符上调用它,并传入一个列表作为参数:

>>> t = ['pining', 'for', 'the', 'fjords']
>>> delimiter = ' '
>>> s = delimiter.join(t)
>>> s
'pining for the fjords'

在这个例子中,分隔符是一个空格,所以 join 在单词之间添加一个空格。如果不使用空格拼接字符串,你可以使用空字符串 '' 作为分隔符。

10.对象和值 #

如果我们执行下面的赋值语句:

a = 'banana'
b = 'banana'

我们知道 a 和 b 都指向一个字符串,但是我们不知道是否他们指向 同一个 字符串。这里有两种可能的状态,如图10-2:状态图所示。

图10-2:状态图

图10-2:状态图

一种情况是,a 和 b 指向两个有相同值的不同对象。 第二种情况是,它们指向同一个对象。

为了查看两个变量是否指向同一个对象,你可以使用 is 运算符。

>>> a = 'banana'
>>> b = 'banana'
>>> a is b
True

在这个例子中,Python仅生成了一个字符串对象,a 和 b 都指向它。但是当你创建两个列表时,你得到的是两个对象:

>>> a = [1, 2, 3]
>>> b = [1, 2, 3]
>>> a is b
False

所以状态图如图10-3:状态图所示。

图10-3:状态图

图10-3:状态图

在这个例子中,我们称这两个列表是 相等(equivalent) 的,因为它们有相同的元素。但它们并不 相同(identical) ,因为他们不是同一个对象。如果两个对象 相同 ,它们也是相等的,但是如果它们是相等的,它们不一定是相同的。

之前,我们一直在等价地使用”对象”和“值”,但是更准确的说,一个对象拥有一个值。 如果你对 [1, 2, 3] 求值,会得到一个值为整数序列的列表对象。 如果另一个列表有同样的元素,我们说它们有相同的值,但是它们并不是同一个对象。

11.别名 #

如果 a 指向一个对象,然后你赋值 b = a ,那么两个变量指向同一个对象:

>>> a = [1, 2, 3]
>>> b = a
>>> b is a
True

状态图如图10-4:状态图所示。

图10-4:状态图

图10-4:状态图

变量和对象之间的关联称为 引用(reference) 。 在这个例子中,有两个对同一个对象的引用。

如果一个对象有多于一个引用,那它也会有多个名称, 我们称这个对象是 有别名的(aliased) 。

如果一个有别名的对象是可变的,对其中一个别名(alias)的改变对影响到其它的别名:

>>> b[0] = 42
>>> a
[42, 2, 3]

尽管这个行为很有用,但是容易导致出现错误。 通常,避免对于可变对象使用别名相对更安全。

对于像字符串这样的不可变对象,使用别名没有什么问题。例如:

a = 'banana'
b = 'banana'

a和 b 是否指向同一个字符串基本上没有什么影响。

12.列表参数 #

当你将一个列表作为参数传给一个函数,函数将得到这个列表的一个引用。如果函数对这个列表进行了修改,会在调用者中有所体现。例如, delete_head 删除列表的第一个元素:

def delete_head(t):
    del t[0]

这样使用这个函数:

>>> letters = ['a', 'b', 'c']
>>> delete_head(letters)
>>> letters
['b', 'c']

参数 t 和变量 letters 是同一个对象的别名。 其堆栈图如图10-5:堆栈图所示。

图10-5:堆栈图

图10-5:堆栈图

由于列表被两个帧共享,我把它画在它们中间。

需要注意的是修改列表操作和创建列表操作间的区别。 例如,append 方法是修改一个列表,而 + 运算符是创建一个新的列表:

>>> t1 = [1, 2]
>>> t2 = t1.append(3)
>>> t1
[1, 2, 3]
>>> t2
None

append修改列表并返回None。

>>> t3 = t1 + [4]
>>> t1
[1, 2, 3]
>>> t3
[1, 2, 3, 4]
>>> t1

运算符 + 创建了一个新列表,而不改变原始的列表。

如果你要编写一个修改列表的函数,这一点就很重要。 例如,这个函数 不会 删除列表的第一个元素:

def bad_delete_head(t):
    t = t[1:]              # 错的!

切片运算符创建了一个新列表,然后这个表达式让 t 指向了它, 但是并不会影响原来被调用的列表。

>>> t4 = [1, 2, 3]
>>> bad_delete_head(t4)
>>> t4
[1, 2, 3]

在 bad_delete_head 的开始处,t 和 t4 指向同一个列表。在结束时,t 指向一个新列表,但是 t4 仍然指向原来的、没有被改动的列表。

一个替代的写法是,写一个创建并返回一个新列表的函数。 例如,tail 返回列表中除了第一个之外的所有元素:

def tail(t):
    return t[1:]

这个函数不会修改原来的列表。下面是函数的使用方法:

>>> letters = ['a', 'b', 'c']
>>> rest = tail(letters)
>>> rest
['b', 'c']

13.术语表 #

列表(list):多个值组成的序列。

元素(element):列表(或序列)中的一个值,也称为项。

嵌套列表(nested list):作为另一个列表的元素的列表。

累加器(accumulator):循环中用于相加或累积出一个结果的变量。

增量赋值语句(augmented assignment):一个使用类似 += 操作符来更新一个变量的值的语句。

归并(reduce):遍历序列,将所有元素求和为一个值的处理模式。

映射(map):遍历序列,对每个元素执行操作的处理模式。

筛选(filter):遍历序列,选出满足一定标准的元素的处理模式。

对象(object):变量可以指向的东西。一个对象有数据类型和值。

相等(equivalent):有相同的值。

相同(identical):是同一个对象(隐含着相等)。

引用(reference):一个变量和它的值之间的关联。别名使用:两个或者两个以上变量指向同一个对象的情况。

分隔符(delimiter):一个用于指示字符串分割位置的字符或者字符串。

14.练习题 #

你可以从在习题10-7的后面查看习题10-1~10-7的答案。

习题10-1 #

编写一个叫做 nested_sum 的函数,接受一个由一些整数列表构成的列表作为参数,并将所有嵌套列表中的元素相加。 例如:

>>> t = [[1, 2], [3], [4, 5, 6]]
>>> nested_sum(t)
21

习题10-2 #

编写一个叫做 cumsum 的函数,接受一个由数值组成的列表,并返回累加和; 即一个新列表,其中第ii个元素是原列表中前i+1i+1个元素的和。 例如:

>>> t = [1, 2, 3]
>>> cumsum(t)
[1, 3, 6]

习题10-3 #

编写一个叫做 middle 的函数,接受一个列表作为参数,并返回一个除了第一个和最后一个元素的列表。 例如:

>>> t = [1, 2, 3, 4]
>>> middle(t)
[2, 3]

习题10-4 #

编写一个叫做 chop 的函数,接受一个列表作为参数,移除第一个和最后一个元素,并返回None。 例如:

>>> t = [1, 2, 3, 4]
>>> chop(t)
>>> t
[2, 3]

习题10-5 #

编写一个叫做“is_sorted“的函数,接受一个列表作为参数, 如果列表是递增排列的则返回 True ,否则返回False。 例如:

>>> is_sorted([1, 2, 2])
True
>>> is_sorted(['b', 'a'])
False

习题10-6 #

如果可以通过重排一个单词中字母的顺序,得到另外一个单词,那么称这两个单词是变位词。 编写一个叫做 is_anagram 的函数,接受两个字符串作为参数, 如果它们是变位词则返回 True 。

习题10-7 #

编写一个叫做 has_duplicates 的函数,接受一个列表作为参数, 如果一个元素在列表中出现了不止一次,则返回 True 。 这个函数不能改变原列表。

"""This module contains a code example related to
Think Python, 2nd Edition
by Allen Downey
http://thinkpython2.com
Copyright 2015 Allen Downey
License: http://creativecommons.org/licenses/by/4.0/
"""

from __future__ import print_function, division

import random


def nested_sum(t):
    """Computes the total of all numbers in a list of lists.
   
    t: list of list of numbers
    returns: number
    """
    total = 0
    for nested in t:
        total += sum(nested)
    return total


def cumsum(t):
    """Computes the cumulative sum of the numbers in t.
    t: list of numbers
    returns: list of numbers
    """
    total = 0
    res = []
    for x in t:
        total += x
        res.append(total)
    return res


def middle(t):
    """Returns all but the first and last elements of t.
    t: list
    returns: new list
    """
    return t[1:-1]


def chop(t):
    """Removes the first and last elements of t.
    t: list
    returns: None
    """
    del t[0]
    del t[-1]


def is_sorted(t):
    """Checks whether a list is sorted.
    t: list
    returns: boolean
    """
    return t == sorted(t)


def is_anagram(word1, word2):
    """Checks whether two words are anagrams
    word1: string or list
    word2: string or list
    returns: boolean
    """
    return sorted(word1) == sorted(word2)


def has_duplicates(s):
    """Returns True if any element appears more than once in a sequence.
    s: string or list
    returns: bool
    """
    # make a copy of t to avoid modifying the parameter
    t = list(s)
    t.sort()

    # check for adjacent elements that are equal
    for i in range(len(t)-1):
        if t[i] == t[i+1]:
            return True
    return False


def main():
    t = [[1, 2], [3], [4, 5, 6]]
    print(nested_sum(t))

    t = [1, 2, 3]
    print(cumsum(t))

    t = [1, 2, 3, 4]
    print(middle(t))
    chop(t)
    print(t)

    print(is_sorted([1, 2, 2]))
    print(is_sorted(['b', 'a']))

    print(is_anagram('stop', 'pots'))
    print(is_anagram('different', 'letters'))
    print(is_anagram([1, 2, 2], [2, 1, 2]))

    print(has_duplicates('cba'))
    print(has_duplicates('abba'))


if __name__ == '__main__':
    main()

习题10-8 #

如果你的班级上有23个学生, 2个学生生日相同的概率是多少? 你可以通过随机产生23个生日,并检查匹配来估算概率。 提示:你可以使用 random 模块中的 randint 函 数来生成随机生日。

可以参考:生日悖论

"""This module contains a code example related to
Think Python, 2nd Edition
by Allen Downey
http://thinkpython2.com
Copyright 2015 Allen Downey
License: http://creativecommons.org/licenses/by/4.0/
"""

from __future__ import print_function, division

import random


def has_duplicates(t):
    """Returns True if any element appears more than once in a sequence.
    t: list
    returns: bool
    """
    # make a copy of t to avoid modifying the parameter
    s = t[:]
    s.sort()

    # check for adjacent elements that are equal
    for i in range(len(s)-1):
        if s[i] == s[i+1]:
            return True
    return False


def random_bdays(n):
    """Returns a list of integers between 1 and 365, with length n.
    n: int
    returns: list of int
    """
    t = []
    for i in range(n):
        bday = random.randint(1, 365)
        t.append(bday)
    return t


def count_matches(num_students, num_simulations):
    """Generates a sample of birthdays and counts duplicates.
    num_students: how many students in the group
    num_samples: how many groups to simulate
    returns: int
    """
    count = 0
    for i in range(num_simulations):
        t = random_bdays(num_students)
        if has_duplicates(t):
            count += 1
    return count


def main():
    """Runs the birthday simulation and prints the number of matches."""
    num_students = 23
    num_simulations = 1000
    count = count_matches(num_students, num_simulations)

    print('After %d simulations' % num_simulations)
    print('with %d students' % num_students)
    print('there were %d simulations with at least one match' % count)


if __name__ == '__main__':
    main()

习题10-9 #

编写一个函数,读取文件 words.txt ,建立一个列表,其中每个单词为一个元素。 编写两个版本,一个使用 append 方法,另一个使用 t = t + [x] 。 那个版本运行得慢?为什么?

"""This module contains a code example related to
Think Python, 2nd Edition
by Allen Downey
http://thinkpython2.com
Copyright 2015 Allen Downey
License: http://creativecommons.org/licenses/by/4.0/
"""

from __future__ import print_function, division

import time


def make_word_list1():
    """Reads lines from a file and builds a list using append."""
    t = []
    fin = open('words.txt')
    for line in fin:
        word = line.strip()
        t.append(word)
    return t


def make_word_list2():
    """Reads lines from a file and builds a list using list +."""
    t = []
    fin = open('words.txt')
    for line in fin:
        word = line.strip()
        t = t + [word]
    return t


start_time = time.time()
t = make_word_list1()
elapsed_time = time.time() - start_time

print(len(t))
print(t[:10])
print(elapsed_time, 'seconds')

start_time = time.time()
t = make_word_list2()
elapsed_time = time.time() - start_time

print(len(t))
print(t[:10])
print(elapsed_time, 'seconds')

习题10-10 #

你可以使用 in 运算符检查一个单词是否在单词表中,但这很慢,因为它是按顺序查找单词。

由于单词是按照字母顺序排序的,我们可以使用两分法(也称二进制搜索)来加快速度, 类似你在字典中查找单词的方法。 你从中间开始,如果你要找的单词在中间的单词之前,你查找前半部分,否则你查找后半部分。

不管怎样,你都会将搜索范围减小一半。 如果单词表有 113,809 个单词,你只需要 17步就可以找到这个单词,或着得出单词不存在的结论。

编写一个叫做 in_bisect 的函数,接受一个已排序的列表和一个目标值作为参数, 返回该值在列表中的位置,如果不存在则返回 None 。

或者你可以阅读 bisect 模块的文档并使用它!

"""This module contains a code example related to
Think Python, 2nd Edition
by Allen Downey
http://thinkpython2.com
Copyright 2015 Allen Downey
License: http://creativecommons.org/licenses/by/4.0/
"""

from __future__ import print_function, division

import bisect


def make_word_list():
    """Reads lines from a file and builds a list using append.
    returns: list of strings
    """
    word_list = []
    fin = open('words.txt')
    for line in fin:
        word = line.strip()
        word_list.append(word)
    return word_list


def in_bisect(word_list, word):
    """Checks whether a word is in a list using bisection search.
    Precondition: the words in the list are sorted
    word_list: list of strings
    word: string
    returns: True if the word is in the list; False otherwise
    """
    if len(word_list) == 0:
        return False

    i = len(word_list) // 2
    if word_list[i] == word:
        return True

    if word_list[i] > word:
        # search the first half
        return in_bisect(word_list[:i], word)
    else:
        # search the second half
        return in_bisect(word_list[i+1:], word)


def in_bisect_cheat(word_list, word):
    """Checks whether a word is in a list using bisection search.
    Precondition: the words in the list are sorted
    word_list: list of strings
    word: string
    """
    i = bisect.bisect_left(word_list, word)
    if i == len(word_list):
        return False

    return word_list[i] == word


if __name__ == '__main__':
    word_list = make_word_list()
    
    for word in ['aa', 'alien', 'allen', 'zymurgy']:
        print(word, 'in list', in_bisect(word_list, word))

    for word in ['aa', 'alien', 'allen', 'zymurgy']:
        print(word, 'in list', in_bisect_cheat(word_list, word))

习题10-11 #

两个单词中如果一个是另一个的反转,则二者被称为是“反转词对”。 编写一个函数,找出单词表中所有的反转词对。

"""This module contains a code example related to
Think Python, 2nd Edition
by Allen Downey
http://thinkpython2.com
Copyright 2015 Allen Downey
License: http://creativecommons.org/licenses/by/4.0/
"""

from __future__ import print_function, division


from inlist import in_bisect, make_word_list


def reverse_pair(word_list, word):
    """Checks whether a reversed word appears in word_list.
    word_list: list of strings
    word: string
    """
    rev_word = word[::-1]
    return in_bisect(word_list, rev_word)
        

if __name__ == '__main__':
    word_list = make_word_list()
    
    for word in word_list:
        if reverse_pair(word_list, word):
            print(word, word[::-1])

习题10-12 #

如果交替的从两个单词中取出字符将组成一个新的单词,这两个单词被称为是“连锁词”。 例如,“ shoe”和“ cold”连锁后成为“schooled”。

  1. 编写一个程序,找出单词表中所有的连锁词。提示:不要枚举所有的单词对。
  2. 你能够找到三重连锁的单词吗?即每个字母依次从3个单词得到。
"""This module contains a code example related to
Think Python, 2nd Edition
by Allen Downey
http://thinkpython2.com
Copyright 2015 Allen Downey
License: http://creativecommons.org/licenses/by/4.0/
"""

from __future__ import print_function, division

from inlist import make_word_list, in_bisect


def interlock(word_list, word):
    """Checks whether a word contains two interleaved words.
    word_list: list of strings
    word: string
    """
    evens = word[::2]
    odds = word[1::2]
    return in_bisect(word_list, evens) and in_bisect(word_list, odds) 
        

def interlock_general(word_list, word, n=3):
    """Checks whether a word contains n interleaved words.
    word_list: list of strings
    word: string
    n: number of interleaved words
    """
    for i in range(n):
        inter = word[i::n]
        if not in_bisect(word_list, inter):
            return False
    return True
        

if __name__ == '__main__':
    word_list = make_word_list()
    
    for word in word_list:
        if interlock(word_list, word):
            print(word, word[::2], word[1::2])

    for word in word_list:
        if interlock_general(word_list, word, 3):
            print(word, word[0::3], word[1::3], word[2::3])

贡献者 #

  1. 翻译:@obserthinker
  2. 校对:@bingjin
  3. 参考:@carfly

推荐阅读 #

推荐一个非常优惠的QMT开户渠道 #
很多喜欢玩量化的同学都想要找一个靠谱且低费率能做自动化的券商。 我之前也推荐过一个渠道,但是因为他们公司内部问题,之前的那个开户渠道也遗憾下线了,今天给大家找到了一个新的渠道,费率如下: 有需要的或有任何疑问的可以直接联系我的微信: 834

有任何问题,可以在公众号后台回复:加群,回答相应验证信息,进入互助群询问。


​Python实用宝典 (pythondict.com)
关注公众号:Python实用宝典
更多精彩文章等你阅读

Powered by BetterDocs

评论(0)

提示:请文明发言

您的邮箱地址不会被公开。 必填项已用 * 标注