首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >处理添加和删除的序列

处理添加和删除的序列
EN

Code Review用户
提问于 2016-05-22 14:50:01
回答 2查看 91关注 0票数 5

我正在开发一个管理列表的程序,并且必须能够插入新的项目,并删除项目的范围。我希望用户能够根据列表的当前状态指定插入和删除,而不必担心以后的操作如何需要一个偏移索引才能处理正确的项。

例:

删除: 4-5 插入: 2,6

将在索引2之前插入一个元素,在原来的元素6之前插入另一个元素,并删除最初位于4和5的项。

我想将这些指令转换为删除后插入的列表,这些插入可以连续执行(上面的操作将变成:

删除4,删除4,插入2,插入4

由于4上的删除移动了下面的操作,所以下一个删除也会在4上执行。2的插入使6的插入右移,但前两个减法使其左移。

我正在寻找一个(希望是可读的)公式,将这些插入和删除的索引转换为它们在deleteinsert列表中的形式。

到目前为止,我有一个相当不可读的python函数,它很难维护,但它似乎输出了正确的值:

代码语言:javascript
运行
复制
ii = jj = kk = 0 # list indices
plus = minus = 0 # plus / minus offset
while ii < len(dellist) or jj < len(addlist):
    if jj < len(addlist): # in the list
        if addlist[jj] == kk: # at the specified index
            addlist[jj] -= minus # deletions happen first, so shift it back
            addlist[jj] += plus # then additions happen, so shift it forward
            jj += 1 # next addition
            plus += 1 # one more item inserted before the others
    if ii < len(dellist): # in the list
        if dellist[ii] == kk: # at the specified index
            dellist[ii] -= minus # previous deletions, so shift back
            ii += 1 # next deletion
            minus += 1 # one more item removed from before the others
    kk += 1 # next list element

我主要关注的是有可读的代码,这些代码以后可以轻松修改;理想情况下,我还需要一些更模块化的代码,尽管我不知道在这种情况下如何实现这一点。

EN

回答 2

Code Review用户

回答已采纳

发布于 2016-05-24 07:19:35

并不是真正的代码评审,而是另一种建议:

为什么不让处理器反向处理列表呢?考虑到所建议的“修改”,先按位置对它们进行排序,然后是最大位置。然后,处理器可以沿着这条线前进,而不必在前面的步骤中处理对列表的修改。

因此,逻辑将更多地如下:

代码语言:javascript
运行
复制
for (pos, mod) in sorted(modifications, reverse=True):
    if mod == 'del':
        del lst[pos]
    elif mod == 'ins':
        lst.insert(pos, "some item")
    else:
        raise ValueError("unknown action")  # Or some other handling.
票数 2
EN

Code Review用户

发布于 2016-05-23 14:46:46

所以我把你的代码变成了一个函数,然后在你给出的例子中运行它。我得到了以下代码:

代码语言:javascript
运行
复制
def shift_indexes(dellist, addlist):
    ii = jj = kk = 0
    plus = minus = 0
    while ii < len(dellist) or jj < len(addlist):
        if jj < len(addlist):
            if addlist[jj] == kk:
                addlist[jj] -= minus
                addlist[jj] += plus
                jj += 1
                plus += 1
        if ii < len(dellist):
            if dellist[ii] == kk:
                dellist[ii] -= minus
                ii += 1
                minus += 1
        kk += 1
    return dellist, addlist

dellist = [4, 5]
addlist = [2, 6]
print('del: {}\nadd: {}'.format(*shift_indexes(dellist, addlist)))

您提供的输入运行良好,但当我将addlist更改为6, 2而不是2, 6时,情况就不一样了。所以我会“白方块”测试你的代码:

代码语言:javascript
运行
复制
if addlist[0] == 0: # 6 == 0 : False
kk += 1             # kk = 1
if addlist[0] == 1: # 6 == 1 : False
kk += 1             # kk = 2
if addlist[0] == 2: # 6 == 2 : False
kk += 1             # kk = 3
if addlist[0] == 3: # 6 == 3 : False
kk += 1             # kk = 4
if addlist[0] == 4: # 6 == 4 : False
kk += 1             # kk = 5
if addlist[0] == 5: # 6 == 5 : False
kk += 1             # kk = 6
if addlist[0] == 6: # 6 == 6 : True
jj += 1             # jj = 1
kk += 1             # kk = 7
if addlist[1] == 7: # 2 == 7 : False
kk += 1             # kk = 8
if addlist[1] == 8: # 2 == 8 : False
...                 # loop for ever

错误很明显!

好的,让我们改变这个。我们知道删除和添加是按顺序进行的,而且顺序很重要!我们应该能够猜测插入和删除应该能够发生在任何地方。我们需要算法来处理任意顺序的数字。

所以老实说,我会推荐一种新算法。

为了简化所有代码,我强烈建议您更改输入,这个输入应该是一个列表,按照您想要添加和删除的顺序排列。此列表中的项应该是(operation, index)

若要保存您,请了解如何更改此窗体的当前输入。你想:

  1. 列两张单子。一个操作,一个索引。
  2. zip将列表放在一起。
  3. 将列表更改为列表,从元组列表(Python2)或元组迭代器(Python3)更改。

因此:

代码语言:javascript
运行
复制
list_ = [list(i) for i in
         zip(['del'] * len(dellist) + ['add'] * len(addlist), dellist + addlist)]

不太好读,但它使算法更好!你的正负方法不起作用,所以我不打算谈修改它。

因此,最简单的方法就是在迭代list_的同时转换它。迭代时,我们想要通过enumerate传递它--这是为了在list_中得到索引,我们还需要操作符和我们想要相对移动的索引。这导致:

代码语言:javascript
运行
复制
for i, (operation, curr_index) in enumerate(list_):

因此,我们想跳过任何我们不知道的操作。如果您稍后决定删除可怕的zip列表理解内容。这是一个简单的if ...: continue

代码语言:javascript
运行
复制
if operation not in ('add', 'del'):
    continue

现在是算法的主要部分。如果运算符添加的是“否则-1”,则希望将该项之后的索引更改为+1。

代码语言:javascript
运行
复制
change = 1 if operation == 'add' else -1

然后,如果索引大于当前项,则希望将更改添加到当前项之后的所有项中。因此:

代码语言:javascript
运行
复制
i += 1
for j, (_, index) in enumerate(list_[i:], i):
    if index >= curr_index:
        list_[j][1] += change

如果我们把这一切合并在一起,你应该得到:

代码语言:javascript
运行
复制
def shift_indexes(dellist, addlist):
    # Transform input to better format
    list_ = [list(i) for i in
             zip(['del'] * len(dellist) + ['add'] * len(addlist), dellist + addlist)]
    for i, (operation, curr_index) in enumerate(list_, 1):
        if operation not in ('add', 'del'):
            continue
        change = 1 if operation == 'add' else -1
        for j, (_, index) in enumerate(list_[i:], i):
            if index >= curr_index:
                list_[j][1] += change
    return list_

如果您拥有的不仅仅是add和del,那么您可能需要使用字典。

我们现有的“字典”是:

代码语言:javascript
运行
复制
d = {
    'add': 1,
    'del': -1
}

要使用本词典,您需要更改if和如何获得change。如果更改不是有效项,则可以使用dict.get获取更改或None,然后可以使用:

代码语言:javascript
运行
复制
change = d.get(operator, None)
if change is None:
    continue

不管怎样,这比你所做的要简单得多。

票数 4
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/129025

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档