为什么这个包含连续重复项的python循环会中断?

为什么这个包含连续重复项的python循环会中断?,python,loops,Python,Loops,我正试图解决这个问题。在这个问题中,我需要迭代一个方向列表(北、南、东、西),并放弃任何相邻的相反方向(北和南,东和西),以返回仅包含非冗余方向的精简数组。当我迭代一个不包含连续重复项的列表时,如[“北”、“南”、“南”、“东”、“西”、“北”、“西”],我的代码工作正常,但当我迭代一个包含连续重复项的列表时,它会崩溃,如[“东”、“东”、“西”]。为什么我的代码会这样做,我如何修复它来处理连续的重复 def dirReduc(arr): for direction in arr[:-1]:

我正试图解决这个问题。在这个问题中,我需要迭代一个方向列表(
北、南、东、西
),并放弃任何相邻的相反方向(
西
),以返回仅包含非冗余方向的精简数组。当我迭代一个不包含连续重复项的列表时,如
[“北”、“南”、“南”、“东”、“西”、“北”、“西”]
,我的代码工作正常,但当我迭代一个包含连续重复项的列表时,它会崩溃,如
[“东”、“东”、“西”]
。为什么我的代码会这样做,我如何修复它来处理连续的重复

def dirReduc(arr):
  for direction in arr[:-1]:
    try:
      gotdata = arr[arr.index(direction)+1] 
    except IndexError:
      gotdata = 'null'
    except ValueError:
      gotdata = 'null'
    if gotdata is 'null':
      if arr == dirReduc(arr):
        return arr
      else:
        return dirReduc(arr)
    elif cancel_pair(direction, arr[arr.index(direction)+1]):
      del arr[arr.index(direction):arr.index(direction)+2]
  return arr

def cancel_pair(dir1, dir2):
  if dir1 in ('NORTH') and dir2 in ('SOUTH') or dir1 in ('SOUTH') and dir2 in ('NORTH'):
    return True
  elif dir1 in ('WEST') and dir2 in ('EAST') or dir1 in ('EAST') and dir2 in ('WEST'):
    return True
  return False
编辑

我把这个放在这里是因为我认为解释和递归版本是有帮助的,但是@Blckknght的答案更优越,因为它做的工作更少(只备份一个元素,而不是每次迭代都重新启动)


这里有一些工作代码。我意识到这有点偏离你的准则。(您可以忽略
取消对
实现;在看到您的实现之前,我编写了自己的实现。您的实现看起来不错。)

我认为您的代码有几个问题:

  • 在迭代时修改方向列表。这通常是一个坏主意,特别是在这里,我认为这可能会导致跳过元素(因为列表的长度正在改变)
  • 您只需通过阵列一次。在Codewars上链接到的问题中,需要在删除取消对后重复该过程
  • 您正在使用
    index
    计算当前索引,但它始终会告诉您要传递的值的第一次出现的索引。相反,您需要自己跟踪索引。我选择只迭代索引,因为我需要使用索引+1
  • 更新

    递归方法可能更容易理解,具体取决于您的编程背景:

    def dirReduc(directions):
        for i in range(len(directions) - 1):
            if cancel_pair(directions[i], directions[i + 1]):
                return dirReduc(directions[:i] + directions[i + 2:])
        return directions
    
    opp={}
    opp['NORTH']='SOUTH'
    opp['EAST']='WEST'
    opp['SOUTH']='NORTH'
    opp['WEST']='EAST'
    def红色(lst):
    i=0
    j=1
    当j
    这是一种更干净的方法,我存储相反的方向,然后在列表上迭代,每次“弹出”相反的元素时都创建一个新的副本

    请记住,输入列表将被此代码修改,因此如果需要,您可能希望传递输入列表的副本。

    此函数中有很多错误。最重要的两个局部错误是:

    • arr.index(direction)
      将始终在
      arr
      中找到
      direction
      的第一个实例,即使您已转到下一个实例

    • >P> > <代码> DEL ARR [X:Y] < /代码>循环>代码> ARR < /C> >,1</p>
    但是,我也不认为你的算法做了它应该做的。我会这样写:

    import re
    _rcd_removals = re.compile(
        r"\b(?:SOUTH NORTH|NORTH SOUTH|WEST EAST|EAST WEST)\b")
    
    def remove_cancelling_directions(dirs):
        """DIRS is a list of uppercase cardinal directions as strings
           (NORTH, SOUTH, EAST, WEST).  Remove pairs of elements that
           cancel each others' motion, e.g. NORTH immediately followed
           by SOUTH.  Modifies DIRS in place and returns nothing."""
    
        dirs[:] = _rcd_removals.sub("", " ".join(dirs)).split()
    
    正则表达式非常擅长对单词序列进行滑动窗口编辑。将其作为一个数组进行处理将变得更加挑剔

    如果需要折叠只有在其他对折叠后才可见的对(例如,
    WEST-SOUTH-NORTH-EAST
    应成为空列表),则应迭代到一个固定点:

    import re
    _rcd_removals = re.compile(
        r"\b(?:SOUTH NORTH|NORTH SOUTH|WEST EAST|EAST WEST)\b")
    _rcd_fixwhite = re.compile(" {2,}")
    
    def remove_cancelling_directions_repeatedly(dirs):
        ds = " ".join(dirs)
        prev_ds = None
        while prev_ds != ds:
            prev_ds = ds
            ds = _rcd_removals.sub("", ds)
            ds = _rcd_fixwhite.sub(" ", ds)
       dirs[:] = ds.split()
    


    1有人能告诉我Python官方文档中声明在迭代列表时对列表进行变异的效果是不可预测的吗?我知道是这样,但我找不到官方规定。(对
    list
    的规范不厌其烦地指出,在对列表进行排序时对其进行变异具有未定义的行为。)

    for
    循环的
    不适合此问题。如果删除一对项目,可能需要回溯以查看是否创建了一对新项目。
    while
    循环更自然:

    opposite_directions = {
        "NORTH": "SOUTH",
        "SOUTH": "NORTH",
        "EAST": "WEST",
        "WEST": "EAST"
    }
    
    def dirReduc(arr):
        i = 0
        while i < len(arr) - 1:
            if arr[i] == opposite_directions[arr[i+1]]:
                del arr[i:i+2]
                if i > 0:
                    i -= 1 # back up a step if we just deleted some moves from the middle
            else:
                i += 1
        return arr
    
    相反方向={
    “北”:“南”,
    “南”:“北”,
    “东”:“西”,
    “西”:“东”
    }
    def直接还原(arr):
    i=0
    而i0:
    i-=1#如果我们只是从中间删除了一些动作,请后退一步
    其他:
    i+=1
    返回arr
    

    我还用一个简单的字典查找替换了
    cancel\u pairs
    函数。Python的字典是很好的,它们通常比一个复杂的< < > > > < <代码> > />代码>另一个>代码>块。

    你的非连续重复列表包含连续的重复“南”、“南”,或者我不知道为什么你认为代码> [东]、“东”、“西”<代码>有连续的重复而不是<代码> [北方]。“南”、“南”、“东”、“西”、“北”、“西”]
    ?请您解释一下这是怎么回事?这对我来说并不明显。此外,您的“不包含连续重复项的列表”示例在一行中有两个南方。另外,请显示
    cancel\u pair
    的代码。您的代码应该做什么?它在做什么?它是如何中断的?第3位或多或少是我猜到的。因此,使用while循环手动处理单步遍历列表会更有意义。我使用
    for
    循环单步遍历列表,使用
    while
    循环重复该过程。尝试运行“我的代码”并在
    循环的同时在
    的顶部打印出
    方向
    ,看看会发生什么。@zwol每次找到匹配项时都需要重新开始。在这个问题的代码战描述中(诚然写得很糟糕),您只删除相邻的对,然后重复。所以ENWSE-->ENWSE,因为没有相邻的取消p
    import re
    _rcd_removals = re.compile(
        r"\b(?:SOUTH NORTH|NORTH SOUTH|WEST EAST|EAST WEST)\b")
    _rcd_fixwhite = re.compile(" {2,}")
    
    def remove_cancelling_directions_repeatedly(dirs):
        ds = " ".join(dirs)
        prev_ds = None
        while prev_ds != ds:
            prev_ds = ds
            ds = _rcd_removals.sub("", ds)
            ds = _rcd_fixwhite.sub(" ", ds)
       dirs[:] = ds.split()
    
    opposite_directions = {
        "NORTH": "SOUTH",
        "SOUTH": "NORTH",
        "EAST": "WEST",
        "WEST": "EAST"
    }
    
    def dirReduc(arr):
        i = 0
        while i < len(arr) - 1:
            if arr[i] == opposite_directions[arr[i+1]]:
                del arr[i:i+2]
                if i > 0:
                    i -= 1 # back up a step if we just deleted some moves from the middle
            else:
                i += 1
        return arr