鱼C论坛

 找回密码
 立即注册
查看: 2176|回复: 3

[已解决]关于列表index再次赋值问题,感觉掉进了一个深坑,请大神讲解~

[复制链接]
发表于 2020-3-2 01:40:21 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
前面发了一个拼图的游戏bug,原帖地址:https://fishc.com.cn/thread-158703-1-2.html利用数字和一个空格模拟九宫格拼图,由于手残在手机上点了已解决,实际未解决,经过一晚上的尝试,又发现了新的问题,问题如下:

第一次运行成功,第二次失败,第三次成功

第一次运行成功,第二次失败,第三次成功

发现问题可能为index索引问题,问题语句为:
  1. list1[list1.index(" ")], list1[list1.index(chocie)] = list1[list1.index(chocie)],list1[list1.index(" ")]
复制代码

尝试将list1.index(" ")改为其他方式获得,例如:
  1. for i in range(9):
  2.     if list[i]=" ":
  3.         zero = i
复制代码

并将上述交换赋值语句改为:
  1. list1[list1.index(chocie)],list1[zero]=list1[zero], list1[list1.index(chocie)]
复制代码

问题可解决
但如果交换赋值语句的顺序颠倒为:
  1. list1[zero],list1[list1.index(chocie)]=list1[list1.index(chocie)], list1[zero]
复制代码

依旧会有问题,感觉是index索引的问题;但是无法理解问题的原因,求大神帮忙解决
附原程序:
  1. import random
  2. def print_chestable(foo):  #定义打印格式,输出九宫格
  3.     num=0
  4.     for i in foo:
  5.         num+=1
  6.         if num%3==0:
  7.             print(i)
  8.         else:
  9.             print(i, end=" ")


  10. def move():  #定义移动步骤
  11.     global list1  #list1为产生九宫格的1-8,以及一个空格组成,格式如[6, ' ', 7, 8, 4, 3, 1, 5, 2]
  12.     dict1={0:[1,3], 1:[0,2,4],2:[1,5],3:[0,4,6],4:[1,3,5,7],5:[2,4,8],6:[3,7],7:[4,6,8],8:[5,7]}
  13.     #对空格位置周围出现的其他可移动位置的列表索引号进行编号

  14.     chocie = int(input("请输入要移动的数字:"))  #用户输入要移动的数字

  15.     '''
  16.     判断用户输入要移动的数字是不是在空格周围可移动的的数字中,如果在:
  17.         交换空格位置和用户输入位置数字的值
  18.         返回新的列表
  19.     如果用户输入要移动的数字不在空格周围可移动的的数字中:
  20.         重新运行这个移动步骤
  21.     '''
  22.     if list1.index(chocie) in dict1[list1.index(" ")]:
  23.         list1[list1.index(" ")], list1[list1.index(chocie)] = list1[list1.index(chocie)],list1[list1.index(" ")]
  24.         return list1
  25.     else:
  26.         move()

  27. '''
  28. 定义游戏开始
  29.     进入循环
  30.         执行移动步骤并输出九宫格
  31.         如果排序正确
  32.             输出赢了
  33.             结束循环
  34. '''
  35. def game_bengin(bar):
  36.     while True:
  37.         print_chestable(move())
  38.         if bar ==[1,2,3,4,5,6,7,8," "]:
  39.             print("你赢了,牛逼")
  40.             break


  41. list1=[i for i in range(1,9)]  #产生[1,2,3,4,5,6,7,8]的列表
  42. list1.append(" ") #产生[1,2,3,4,5,6,7,8," "]的列表
  43. random.shuffle(list1) #产生[1,2,3,4,5,6,7,8," "]的洗牌后列表
  44. print_chestable(list1) #初始化
  45. game_bengin(list1) #运行游戏

复制代码

最佳答案
2020-3-2 10:13:30
list1[list1.index(" ")], list1[list1.index(chocie)] = list1[list1.index(chocie)],list1[list1.index(" ")]这一步造成重复,
先执行list1[list1.index(" ")] = list1[list1.index(chocie)] (直接写chocie就行了)
再执行list1[list1.index(chocie)] = list1[list1.index(" ")] (直接写' '就行了)
造成了重复,因为空格已经改成了choice
建议改成
  1.     if list1.index(chocie) in dict1[list1.index(" ")]:
  2.         s_pos = list1.index(" ")     #空格所在位置
  3.         c_pos = list1.index(chocie)  #输入数字所在的位置
  4.         list1[s_pos] = chocie
  5.         list1[c_pos] = ' '
  6.         return list1
复制代码





小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2020-3-2 10:13:30 | 显示全部楼层    本楼为最佳答案   
list1[list1.index(" ")], list1[list1.index(chocie)] = list1[list1.index(chocie)],list1[list1.index(" ")]这一步造成重复,
先执行list1[list1.index(" ")] = list1[list1.index(chocie)] (直接写chocie就行了)
再执行list1[list1.index(chocie)] = list1[list1.index(" ")] (直接写' '就行了)
造成了重复,因为空格已经改成了choice
建议改成
  1.     if list1.index(chocie) in dict1[list1.index(" ")]:
  2.         s_pos = list1.index(" ")     #空格所在位置
  3.         c_pos = list1.index(chocie)  #输入数字所在的位置
  4.         list1[s_pos] = chocie
  5.         list1[c_pos] = ' '
  6.         return list1
复制代码





评分

参与人数 1荣誉 +1 鱼币 +1 贡献 +1 收起 理由
l0stparadise + 1 + 1 + 1 最佳答案设错了,这个答案不对,楼下是对的

查看全部评分

小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 2 反对 0

使用道具 举报

发表于 2020-3-2 13:05:27 | 显示全部楼层
显然,bug 是由下面这行代码产生的

  1. list1[list1.index(" ")], list1[list1.index(chocie)] = list1[list1.index(chocie)], list1[list1.index(" ")]
复制代码


为了方便讨论,我们简化一下问题,考虑下面这个情况

  1. ls = [1, 2]
  2. ls[ls.index(1)], ls[ls.index(2)] = 2, 1  # 试图交换 1、2,使 ls 变为 [2, 1]
  3. print(ls)
复制代码

上面这段代码的运行结果为
  1. [1, 2]
复制代码


可以看到,ls 并未改变

这个问题与楼主遇到的问题本质上是一样的,即在修改列表过程中,调用列表的 index 方法,列表却并未能如预期那样改变

实际上,这种现象出现的原因主要是因为 index 方法调用与修改列表之间存在先后顺序的问题

  1. ls[ls.index(1)], ls[ls.index(2)] = 2, 1
复制代码


上面这行代码进行了如下几个操作
1. 计算 ls.index(1),结果为 0
2. 将 2 赋值给 ls[0],此时 ls 的值为 [2, 2]
3. 计算 ls.index(2)(注意此时 ls 已经不是原来的 [1, 2],而是 [2, 2]),结果为 0
4. 将 1 赋值给 ls[0],ls 的值为 [1, 2]

也就是说 ls 的值经过了这样一个变化:[1, 2] --> [2, 2] --> [1, 2]



下面通过一些代码验证上述想法

  1. class NList(list):
  2.     def index(self, val):
  3.         print(f"当前列表的值为:{self}")
  4.         res = super().index(val)
  5.         print(f"返回值为:{res}")
  6.         return res

  7. nls = NList([1, 2])
  8. nls[nls.index(1)], nls[nls.index(2)] = 2, 1
  9. print(nls)
复制代码

运行结果如下
  1. 当前列表的值为:[1, 2]
  2. 返回值为:0
  3. 当前列表的值为:[2, 2]
  4. 返回值为:0
  5. [1, 2]
复制代码


代码中,定义了一个继承了 list 的类 NList,并重写了 index 方法,使其在调用 index 方法时,打印一些信息

从运行结果中,我们可以看到

在执行 nls.index(2) 这个操作的时候,列表 nls 的值已经变为 [2, 2]

那么 nls.index(2) 就将返回 0,然后再将 1 赋值给 nls[0],最终 nls 的值就为 [1, 2]

所以,看起来 nls 好像 ”从未改变“,实际上,它是经历了一个变化过程,又变回了原来的样子



最后,回到最初的问题

  1. list1[list1.index(" ")], list1[list1.index(chocie)] = list1[list1.index(chocie)], list1[list1.index(" ")]
  2. list1[list1.index(" ")], list1[list1.index(chocie)] = chocie, " "
复制代码


上面这两行代码是等价的,都是试图交换 chocie 和 " " 在 list1 中的位置

但由于 list1.index(chocie) 这一步是发生在 list1[list1.index(" ")] = chocie 之后,所以就可能会发生问题

为什么说是可能,而不是一定呢

看下面的代码

  1. >>> ls = [1, 2]
  2. >>> # ls[ls.index(1)], ls[ls.index(2)] = 2, 1  # 不能交换 ls 中 1 和 2 的位置,上面已解释
  3. >>> # 交换一下赋值顺序
  4. >>> ls[ls.index(2)], ls[ls.index(1)] = 1, 2
  5. >>> ls
  6. [2, 1]   # 1 和 2 成功交换位置
  7. >>> ls[ls.index(2)], ls[ls.index(1)] = 1, 2
  8. >>> ls
  9. [2, 1]   # 1、2 位置不变
复制代码


可以看到在利用 ls[ls.index(2)], ls[ls.index(1)] = 1, 2 成功交换一次之后

再尝试利用 ls[ls.index(2)], ls[ls.index(1)] = 1, 2 交换的时候,并未成功



第一次交换的过程如下:
1. 计算 ls.index(2),结果为 1
2. 将 1 赋值给 ls[1],此时 ls 的值为 [1, 1]
3. 计算 ls.index(1)(注意此时 ls 已经不是原来的 [1, 2],而是 [1, 1]),结果为 0
4. 将 2 赋值给 ls[0],ls 的值为 [2, 1]

也就是说 ls 的值经过了这样一个变化:[1, 2] --> [1, 1] --> [2, 1]

第二次交换的过程如下:
1. 计算 ls.index(2),结果为 0
2. 将 1 赋值给 ls[0],此时 ls 的值为 [1, 1]
3. 计算 ls.index(1)(注意此时 ls 已经不是原来的 [2, 1],而是 [1, 1]),结果为 0
4. 将 2 赋值给 ls[0],ls 的值为 [2, 1]

也就是说 ls 的值经过了这样一个变化:[2, 1] --> [1, 1] --> [2, 1]


上述过程表明

  1. list1[list1.index(" ")], list1[list1.index(chocie)] = chocie, " "
复制代码


如果你不停地输入同样的数字(即 chocie 每次都一样),那么上面这行代码至多只在第一次产生效果

所以,就出现了楼主的图中,第一次输入 5,正常交换,后面再输入 5 无法交换的问题
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 1 反对 0

使用道具 举报

 楼主| 发表于 2020-3-2 15:37:28 | 显示全部楼层
EthanHsiung 发表于 2020-3-2 10:13
list1, list1 = list1,list1这一步造成重复,
先执行list1 = list1 (直接写chocie就行了)
再执行list1 =  ...

最佳答案设错了,你这个答案不对。。。。。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2026-3-1 14:44

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表