喵喵时光机
Volker和torek,感谢您的评论,我发现它们与问题最相关。为题外话道歉,我还没有太多在 StackOverflow 上提问的经验。torek引用的文章重点是设计一种可实现最高效率的算法。这确实是一项了不起的成就,但在我的特定应用程序中,我将使用此算法处理仅包含 10 个项目的列表,并且仅在几个小时内执行一次,因此我不需要它来获得一流的效率。因此,我对如何做到这一点有了一个相当简单的想法,而且它似乎有效。这个想法是计算所有元素的新旧位置之间的差异,找到具有最大偏移的元素,在输出报告中标记它是如何移动的,然后将其移动到新位置。然后重复它,直到列表相同。在此操作之前,应解决列表组成的差异。我不能保证它在大列表上完全按预期工作,它们之间有很多差异,但我需要它来处理相对较短的列表,只有 1-2 处更改,所以它应该对我有用。这是一个示例代码:// diff describes how an updated position of an element is different from an old one// it's either a new element, or it's shifted by "shift" in "direction", or position didn't changetype diff struct { shift int direction direction isNew bool}type direction intconst ( up = direction(-1) down = direction(1) none = direction(0))func hasShifts(shifts []diff) bool { for _, d := range shifts { if d.shift != 0 { return true } } return false}func diffs(old, updated []string) (shifts []diff) { for i, newEl := range updated { for j, oldEl := range old { if newEl == oldEl { var dir direction switch { case i < j: dir = up case i > j: dir = down default: dir = none } shifts = append(shifts, diff{int(math.Abs(float64(i-j))), dir, false}) break } } if len(shifts) < i+1 { shifts = append(shifts, diff{isNew: true}) } } return}func move(list *[]string, position, shift int, dir direction) { for i := position; i != position + shift * int(dir); i += int(dir) { (*list)[i], (*list)[i+int(dir)] = (*list)[i+int(dir)], (*list)[i] }}func compare(old, updated []string) (report []string) { report = append([]string{}, updated...) // first, find and mark updated elements; add them to the old list shifts := diffs(old, updated) for i, d := range shifts { if d.isNew { old = append(old[:i], append(updated[i:i+1], old[i:]...)...) report[i] = "*" + report[i] } } // remove elements of the old list that aren't present in the updated shifts = diffs(updated, old) // reversed n := 0 for i, d := range shifts { if !d.isNew { old[n] = old[i] n++ } } old = old[:n] // until lists are identical shifts = diffs(old, updated) for hasShifts(shifts) { // find an element with the largest shift highest := 0 for i, d := range shifts { if d.shift > shifts[highest].shift || (d.shift == shifts[highest].shift && d.direction == up) { highest = i } } // mark in report how this element shifted if shifts[highest].direction == up { report[highest] = "↑" + report[highest] } else { report[highest] = "↓" + report[highest] } // move this element in the old list to its updated place for i, oldEl := range old { if oldEl == updated[highest] { move(&old, i, shifts[highest].shift, shifts[highest].direction) break } } // update diffs shifts = diffs(old, updated) } return}该函数compare(old, updated)返回一个字符串列表,以下列方式说明两个列表之间的变化:它具有与更新列表相同的顺序和组成;将前缀“*”添加到更新列表的所有新元素;将前缀“↑”添加到需要向上移动(朝向列表开头)以将旧列表转换为更新列表的元素;需要向下移动的元素添加前缀“↓”;它优先考虑“向上”移位(如果两个相邻元素交换位置)。让我们使用以下列表来测试它:var ( old = []string{ "first", "second", "third", "fourth", "fifth", "sixth", "seventh", "eighth", "ninth", "tenth", } updated = []string{ "eighth", "second", "third", "first", "fourth", "new", "sixth", "seventh", "tenth", "ninth", })结果将是:↑eighthsecondthird↓firstfourth*newsixthseventh↑tenthninth这是一个工作的游乐场示例。我很确定它远非完美,但它肯定会满足我的需求。