我正在尝试解决this问题。在问题中我需要迭代一个方向列表(NORTH, SOUTH, EAST, WEST
)并丢弃任何相邻的相反方向(NORTH
和SOUTH
,EAST
和WEST
)返回仅包含非冗余方向的简化数组。当我遍历不包含连续重复项的列表(例如["NORTH", "SOUTH", "SOUTH", "EAST", "WEST", "NORTH", "WEST"]
)时,我的代码工作正常,但是当我遍历具有连续重复项的列表时,它会中断,例如['EAST', 'EAST', 'WEST']
。为什么我的代码会这样做,如何修复它以处理连续的重复?
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
答案 0 :(得分:4)
String s = "abc,xyz,lmn,ijk";
int counter = 0;
char[] ch = s.toCharArray();
for (int i = 0; i < ch.length; i++) {
if (ch[i] == ',') {
counter++;
}
}
循环不适合此问题。如果删除一对项目,则可能需要回溯以查看是否创建了新对。 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
函数。 Python的词典很棒,而且它们通常比复杂的cancel_pairs
/ if
块更好。
答案 1 :(得分:0)
修改强>
我离开这里是因为我认为解释和递归版本是有帮助的,但@ Blckknght的答案是优越的,因为它做的工作较少(通过仅备份一个元素而不是重新启动每次迭代)。
这里有一些工作代码。我意识到它与您的代码有点不同。 (你可以忽略cancel_pair
实现;我在看到你的之前写了我自己的。你的看起来很好。)
def cancel_pair(dir1, dir2):
return tuple(sorted((dir1, dir2))) in (("NORTH", "SOUTH"), ("EAST", "WEST"))
def dirReduc(directions):
did_something = True
while did_something:
did_something = False
for i in range(len(directions) - 1):
if cancel_pair(directions[i], directions[i + 1]):
did_something = True
directions = directions[:i] + directions[i + 2:]
break
return directions
我认为您的代码存在一些问题:
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
答案 2 :(得分:0)
opp = {}
opp['NORTH'] = 'SOUTH'
opp['EAST'] = 'WEST'
opp['SOUTH'] = 'NORTH'
opp['WEST'] = 'EAST'
def red(lst):
i = 0
j = 1
while j< len(lst):
if(opp[lst[i]] == lst[j]):
lst[i] = 0
lst[j] = 0
lst = [x for x in lst if x != 0]
i =0
j =1
else:
i+=1
j+=1
print(i,j)
这是一种更简洁的方法,我存储相反的方向,然后迭代列表,每当我'弹出'相反的元素时制作一个新的副本。
请记住,此代码将修改输入列表,因此您可能希望在需要时传递输入列表的副本。
答案 3 :(得分:-2)
此功能中存在批次错误。最重要的两个本地错误是:
arr.index(direction)
将始终在direction
中找到arr
的第一个实例,即使您已经进入下一个}}
del arr[x:y]
位于arr
之上,will have unpredictable results。 1
但是,我认为你的算法不会做它应该做的事情。我会这样写:
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
的规范不遗余力地指出在排序时改变列表它有未定义的行为。)