如何迭代一个列表中的列表并更改元素值?

5

我有一个列表的列表:

game = [['X', 'O', 'O'], ['', '', 'O'], ['', '', '']]

我想要更改所有的值:

  • 如果元素是'X',则将其设置为1。
  • 如果元素是'O',则将其设置为2。
  • 如果元素是“”(空),则将其设置为0(零)。

输出结果如下:

game = [['1', '2', '2'], ['0', '0', '2'], ['0', '0', '0']]

我可以像这样进行迭代:

for list in game:
  for element in list:
    ...

但是要更改我的列表中的元素则另当别论,我可以通过使用append创建一个新列表,但我得到了类似于[1, 2, 2, 0, 0, 2, 0, 0, 0]的结果。


你是否想要预定义你的因式分解,例如 X -> 1O -> 2 等(几乎总是不想手动完成)?或者任何一种一致的因式分解都可以吗? - jpp
8个回答

5

使用字典和列表推导:

>>> game = [['X', 'O', 'O'], ['', '', 'O'], ['', '', '']]
>>> d = {'X': '1', 'O': '2', '': '0'}
>>> [[d[x] for x in row] for row in game]
[['1', '2', '2'], ['0', '0', '2'], ['0', '0', '0']]

1
最Pythonic的解决方案 - John Coleman
为什么要创建一个新列表,如果我们可以更新现有的列表呢? - mad_
@mad_ 这取决于需求。对于足够小的列表,使用列表推导通常是最简洁和快速的方法。 - Eugene Yarmash
@mad_,因为时间复杂度相同,而内存可能不是问题。[如果内存很重要,另一种数据结构可能更合适。] - jpp

2
许多很好的答案已经有了。我会加入一个使用map()的一行代码,只是因为它很有趣:
[list(map(lambda x: {'X':'1', 'O':'2', '':'0'}.get(x), i)) for i in game]

# [['1', '2', '2'], ['0', '0', '2'], ['0', '0', '0']]

解释: map() 本质上是在传递的对象 i 上应用一个函数,这些对象是 game 的子列表。在这种情况下,我们想要在 game 中的每个子列表(i) 中的每个标记(x) 上应用得分字典中的 .get(x) 。与列表推导结合使用,它会将所有转换后的分数作为新的 listlists 返回。

我更喜欢这个比使用 map() 的答案(更易读)。你也可以使用 [list(map(lambda x: {'X':'1', 'O':'2'}.get(x, '0'), i)) for i in game],如果嵌套列表中包含任何值而不是 'X''O',则默认为 '0' 值。 - benvc
同意,尽管在这种情况下,我更倾向于明确定义 {'': '0'},因为 ['X', 'O', 'foo'] 也会返回 ['1', '2', '0'],这可能不是预期的结果。我们不确定在未定义 x 的情况下 OP 想要什么,那么就落在了 .get(x, default_value) 的用例下。 - r.ook
毫无疑问,做出默认假设可能会导致问题。我们可能不知道 OP 正在开发一个“tic, tac, foo, bar, baz”的游戏 :) - benvc

1

现在你已经有了一个答案列表,该列表致力于耗尽基于简单映射的列表值转换的所有可能性,似乎我们不包括使用map()的解决方案就有些过失。所以这里是:

game = [['X', 'O', 'O'], ['', '', 'O'], ['', '', '']]

nums = [list(map(lambda x: '2' if x == 'O' else '1' if x == 'X' else '0', row)) for row in game]
print(nums)
# OUTPUT
# [['1', '2', '2'], ['0', '0', '2'], ['0', '0', '0']]

请参考@Idlehands提供的更好的map()答案。 - benvc

0

尝试枚举列表:

game = [['X', 'O', 'O'],['', '', 'O'],['', '', '']]

for list in game:
  for num,element in enumerate(list):
    if element == "X":
      list[num] = "1"
    if element == "O":
      list[num] = "2"
    if element == "":
      list[num] = "0"

print(game)   

这是针对相对较少数据的工作,但如果我们必须映射大量值,则会变得混乱。使用字典或其他更优雅的数据结构。 - mad_

0

使用numpy非常简单。

import numpy as np
game = np.array(game)

game[game=='X'] = 1
game[game=='O'] = 2
game[game==''] = 0

print(game.tolist())
# [['1', '2', '2'], ['0', '0', '2'], ['0', '0', '0']]

print(game.ravel().tolist())
# ['1', '2', '2', '0', '0', '2', '0', '0', '0']

2
我认为在这里使用numpy是过度的,因为没有需要进行向量化操作。你正在从现有列表创建一个numpy数组->执行numpy操作->再将numpy转换为列表。 - mad_

0
创建一个映射字典并迭代列表(不创建新列表)。
d={'X':'1','O':'2','':0}
for i in game:
    for idx,value in enumerate(i):
        i[idx]=d.get(value, str(value))

print(game) #[['1', '2', '2'], ['0', '0', '2'], ['0', '0', '0']]

如果你想创建一个全新的列表
d={'X':'1','O':'2','':0}
new_list=[]
for i in game:
    temp=[]
    for idx,value in enumerate(i):
        temp.append(d.get(value, str(value)))
    new_list.append(temp)

0

我会在字典中定义规则,获取值并对空字符串使用默认值0。

我也使用了列表推导。

仅限于列表推导:

new_game = [[rules.get(item, 0) for item in li] for li in game]

使用辅助函数:
game = [['X', 'O', 'O'],
['', '', 'O'],
['', '', '']]

rules = { 'X': '1', 'O': '2' }

def update_list(li):
  return [rules.get(item, 0) for item in li]

new_game = [update_list(li) for li in game]

print (new_game)

# [[1, 2, 2], [0, 0, 2], [0, 0, 0]]

0

new_list = [] for list in game: new_sublist = [] for item in list: ... new_sublist += new_item new_list += new_sublist

这应该可以使用循环的方法为您获得一个二维列表。


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