如何查找两个列表之间的更改,其中包含不可移动的项目(PHP)

发布于 2024-10-18 10:22:53 字数 516 浏览 2 评论 0原文

我正在尝试获取两个文章列表之间的更改,以便为两个列表之间的过渡设置动画。可以添加、删除或移动(不可交换)文章。

但是,有些文章无法移动,并且在每次转换中,所有其他文章都应移至这些文章下方。

例如,如果每个数字代表一个文章id,粗体代表不可移动的文章,那么: [1, 2, 3, 4, 5, 6] 可能会变成:[2, 4, 1 , 6, 7]

我需要计算出所需的更改,例如在这种情况下:

  • 在 4 之后移动 1
  • 删除 5
  • 在 6 之后添加 7

我一直在使用 diff 算法,但是它不理解不可移动的项目,所以它可能建议:

  • 将 2 移至开头
  • 在 2 之后移动 4
  • 删除 5
  • 在 6 之后添加 7

我尝试了各种方法,但无法让它可靠地工作。

I'm trying to get the changes between two lists of articles in order to animate the transition between the two lists. Articles can be added, removed or moved (not swapped).

However some articles can't be moved, and in each transition all other articles should be moved below those articles.

For example, if each number represents an article id, and bold represents immovable articles, then:
[1, 2, 3, 4, 5, 6] might become: [2, 4, 1, 6, 7]

I need to work out the changes required, for example in this case:

  • Move 1 after 4
  • Remove 5
  • Add 7 after 6

I have been using a diff algorithm, however it doesn't understand immovable items, so it might suggest:

  • Move 2 to the beginning
  • Move 4 after 2
  • Remove 5
  • Add 7 after 6

I've tried various things, but can't get it to work reliably.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

本宫微胖 2024-10-25 10:22:53

将不可移动的项目向左移动 3 个位置与将其旁边的 3 个可移动的项目向右移动 1 个位置是一样的。使用当前的 diff 算法,但是当它想要将不可移动的项目移至其旁边的项目时。


UPD。每篇文章无需多次移动。

Transformations:

1. Remove numbers that are not in the second list (for each item n if not in_list(final_list) then say(n removed)).
   [1 2* 4* 5 6] // say("remove 3")
   [1 2* 4* 6]   // say("remove 5")       
2. Make an empty list size of the final list.
   [_ _ _ _ _]
3. Prefill it with immovable numbers in their final positions.
   [2* 4* _ _ _]
4. Loop through movable items from the first list moving them to their final positions
   [2* 4* 1 _ _] // say("move 1 after 4")
   [2* 4* 1 6 _] // say("move 6 after 1")
5. Add new items
   [2* 4* 1 6 7] // say("add 7 after 6")

这是一个有趣的问题!

Moving an immovable item 3 places left is the same thing as moving 3 movable items next to it 1 place right. Use your current diff algorithm, but when it wants to move an immovable item switch to those next to it instead.


UPD. Without multiple moves per article.

Transformations:

1. Remove numbers that are not in the second list (for each item n if not in_list(final_list) then say(n removed)).
   [1 2* 4* 5 6] // say("remove 3")
   [1 2* 4* 6]   // say("remove 5")       
2. Make an empty list size of the final list.
   [_ _ _ _ _]
3. Prefill it with immovable numbers in their final positions.
   [2* 4* _ _ _]
4. Loop through movable items from the first list moving them to their final positions
   [2* 4* 1 _ _] // say("move 1 after 4")
   [2* 4* 1 6 _] // say("move 6 after 1")
5. Add new items
   [2* 4* 1 6 7] // say("add 7 after 6")

It was a fun problem to solve!

来日方长 2024-10-25 10:22:53

这是最终的代码,感谢 Alexey:

$immovable = array(2);
$current = array(1,2,8,3,4,5,6);
$new = array(2,7,6,5,4,3,1);

$additions = $additionsCopy = array_diff($new, $current);
foreach($additions as $key => $addition) {
  $after = array_key($new, $addition)-1;
  $additions[$key] = array(
    'value' => $addition, 
    'after' => ($after < 0 ? 0 : $new[$after])
  );
}
for($key = 0; $key < count($new); $key++) {
  if(in_array($new[$key], $additionsCopy)) 
    $new = array_remove($new, $key--);
}

$removals = array_diff($current, $new);
for($key = 0; $key < count($current); $key++) {
  if(in_array($current[$key], $removals)) 
    $current = array_remove($current, $key--);
}

$lastImmovable = -1;
foreach($new as $key => $item) if(in_array($item, $immovable)) 
  $lastImmovable = $key;

$prev = $lastImmovable < 0 ? 0 : $new[$lastImmovable];
foreach($new as $key => $item) if (!in_array($item, $immovable)) {
  $moves[] = array('value' => $item, 'after' =>$prev);
  $prev = $item;
}

此时我们可以执行 $removals,然后执行 $moves 然后 $additions

Here's the final code, thanks to Alexey:

$immovable = array(2);
$current = array(1,2,8,3,4,5,6);
$new = array(2,7,6,5,4,3,1);

$additions = $additionsCopy = array_diff($new, $current);
foreach($additions as $key => $addition) {
  $after = array_key($new, $addition)-1;
  $additions[$key] = array(
    'value' => $addition, 
    'after' => ($after < 0 ? 0 : $new[$after])
  );
}
for($key = 0; $key < count($new); $key++) {
  if(in_array($new[$key], $additionsCopy)) 
    $new = array_remove($new, $key--);
}

$removals = array_diff($current, $new);
for($key = 0; $key < count($current); $key++) {
  if(in_array($current[$key], $removals)) 
    $current = array_remove($current, $key--);
}

$lastImmovable = -1;
foreach($new as $key => $item) if(in_array($item, $immovable)) 
  $lastImmovable = $key;

$prev = $lastImmovable < 0 ? 0 : $new[$lastImmovable];
foreach($new as $key => $item) if (!in_array($item, $immovable)) {
  $moves[] = array('value' => $item, 'after' =>$prev);
  $prev = $item;
}

At this point we can perform $removals, then $moves then $additions

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文