Применение CollectionDifference к NSTableView - PullRequest
0 голосов
/ 28 апреля 2020

Для этого примера предположим, что я сгенерировал CollectionDifference из массива ann Int, а затем вызвал inferringMoves для него следующим образом

let a = [18, 18, 19, 11]
let b = [11, 19]
let diff = b.difference(from: a).inferringMoves()

for change in diff {
    switch change {
    case let .insert(offset, _, associatedWith):
        if let from = associatedWith {
            print("MOVE", from, offset)
        } else {
            print("INSERT", offset)
        }
    case let .remove(offset, _, associatedWith):
        // If it is a MOVE it was already recorded in .insert
        if associatedWith == nil {
            print("REMOVE", offset)
        }
    }
}

Теперь мне нужно взять массив изменений и канал это NSTableViews обновить методы

  • insertRows
  • removeRows
  • moveRow

таким образом Применимся чисто. Моя проблема здесь - смещения для move записей. Приведенный выше фрагмент кода дает:

REMOVE 1
REMOVE 0
MOVE 2 1

Теперь, очевидно, я не могу назвать removeRows для 0 и 1, а затем moveRow(2, 1), но это то, что предлагает diff.

Как я могу применить это чисто?

Проблема, кажется, в том, что NSTableView немедленно обновляет свои внутренние значения при применении вставки / удаления, поэтому перемещение не будет работать.

1 Ответ

1 голос
/ 01 мая 2020

Краткий ответ:

inferringMoves() не делает то, что вы думаете, что он делает. Внимательно посмотрите на результат, в частности значение associatedWith, и разработайте алгоритм, который фактически производит удаление, вставку и ходов , которые вам нужны - inferringMoves() на самом деле не производит никаких ходов. ..

Длинный ответ:

Ваш вопрос заинтриговал меня, так как я никогда раньше не смотрел на CollectionDifference, поэтому я мог бы взглянуть на него. Первый шаг - поиск по Inte rnet, это приводит к появлению документации Apple (как обычно, плохой, она написана для тех, кто уже знает семантику, почему они больше не могут предоставить приличную документацию - большая часть приличного материала находится в их "архив", но я не согласен ...) и ряд сайтов, описывающих эту функцию и включая пример кода. Отчасти этот пример кода отличается от вашего, но не расстраивайтесь, потому что он тоже не работает.

Почему этот длинный прогон? То, что вы не можете найти работающий код, заставляет задуматься, страдаете ли вы от «лихорадки блокировки», и ваш мозг переполнен. Весь код действительно не работает? Ну, это работает для некоторых наборов данных, но не в общем случае, Apple, называя зверя inferringMoves, является чем-то вроде задницы, она выводит пары операций удаления и вставки в последовательности, которые вместе имеют эффект перемещения элемента. но на самом деле это не выводит одну операцию перемещения.

Или так говорит мой возможно (больше, чем обычно) переполненный мозг. Читайте дальше и решите, есть ли у меня лихорадка блокировки или нет ...

Давайте посмотрим на ваши данные и посмотрим, что выдает difference и как каждый шаг меняет ввод:

Input: [18, 18, 19, 11]

Sequence of changes from `difference` and the changing sequence:
    remove(offset: 2, element: 19, associatedWith: -) => [18, 18, 11]
    remove(offset: 1, element: 18, associatedWith: -) => [18, 11]
    remove(offset: 0, element: 18, associatedWith: -) => [11]
    insert(offset: 1, element: 19, associatedWith: -) => [11, 19] CORRECT

Что в этой последовательности важно, чтобы offset на любом шаге учитывал все предыдущие шаги, то есть это смещение промежуточного результата.

Now inferringMoves устанавливает для поля associatedWith значение укажите remove/insert пары, которые образуют ход, применяя это к difference ваших данных, вы получите:

remove(offset: 2, element: 19, associatedWith: 1)
remove(offset: 1, element: 18, associatedWith: -)
remove(offset: 0, element: 18, associatedWith: -)
insert(offset: 1, element: 19, associatedWith: 2)

Таким образом, первое и последнее действия выводятся в виде пары ходов.

Вы решили, и вы не одиноки в этом решении, что действие вставки было тем, когда должно быть выполнено перемещение, давайте посмотрим, что произойдет:

[18, 18, 19, 11]
remove(offset: 2, element: 19, associatedWith: 1) => [18, 18, 19, 11]
    Noop as part of a move pair
remove(offset: 1, element: 18, associatedWith: -) => [18, 19, 11]
    Item 1 was 18 so this seems valid...
remove(offset: 0, element: 18, associatedWith: -) => [19, 11]
    Item 0 is not 18 so this looks like things are going wrong
insert(offset: 1, element: 19, associatedWith: 2) => Oops
    Second action of a move pair, Error item 1 is not 19 and there is no item 2

Как вы обнаружили, это не работает. Другие сотрудники inte rnet решили, что это действие по удалению - это движение, лучше ли они?

[18, 18, 19, 11]
remove(offset: 2, element: 19, associatedWith: 1) => [18, 19, 18, 11]
    First of pair, do the move
remove(offset: 1, element: 18, associatedWith: -) => [18, 18, 11]
    Warning bell the item removed is 19 not 18 as the action expects
remove(offset: 0, element: 18, associatedWith: -) => [18, 11]
    Yah, item 0 is 18, this action is "correct" in isolation
insert(offset: 1, element: 19, associatedWith: 2) => [18, 11]
    Second of pair, so NOOP

Это тоже не сработает, так что не расстраивайтесь, что ваш не сделал " Так как я до сих пор не нашел какой-либо код в inte rnet, который действительно работает (это не значит, что его там нет), то ошибаться часто встречается, вероятно, частично из-за множества простых примеров, работающих случайно.

Ключом к решению проблемы является выяснение (поскольку Apple не дает понять), что значение associatedWith - это индекс, который будет (для будущей вставки) или был (для удаления из прошлого) ) выполненный индекс в последовательности, как он существует / существовал в то время, когда связанное действие выполняется / имело место.

Например, первое действие для ваших данных - remove(offset: 2, element: 19, associatedWith: 1), которое не ' Это означает, что вы можете переместить элемент в индекс 1 в последовательности current , но в индекс 1 в последовательности, поскольку он будет существовать при выполнении связанного insert(offset: 1, element: 19, associatedWith: 2). Существует два промежуточных действия удаления между удалением и вставкой пары, поэтому последовательность будет меняться.

Чтобы получить ( не единственное ) рабочее решение, которое вы можете опубликовать, обработайте результат из inferringMoves() со следующим набросанным алгоритмом:

  1. Удалите все операции удаления со значением associatedWith и отрегулируйте значения offset во всех следующих операциях, учитывая, что элемент, который должен быть удален, является все еще в последовательности; и
  2. Отрегулируйте значение associatedWith, чтобы оно было текущим смещением элемента, который не был удален с помощью операции парного удаления, которая была удалена.

Это приведет к нулевой последовательности или более операций удаления и вставки без значений associatedWith и одно или несколько действий вставки со значениями associatedWith, представляющими перемещения.

Применение реализации приведенного выше эскиза алгоритма к вашим данным дает:

[18, 18, 19, 11]
remove(offset: 1, element: 18, associatedWith: -) => [18, 19, 11]
remove(offset: 0, element: 18, associatedWith: -) => [19, 11]
insert(offset: 2, element: 19, associatedWith: 0) => [11, 19]
    a move: insert at offset, remove at associatedWith

Реализация этого или другого алгоритма, как и SO, не является услугой написания кода, оставлена ​​вам. Надеюсь, приведенное выше объяснение имеет смысл! Если вы застряли в своей реализации, вы можете задать новый вопрос, описать ваш алгоритм, показать ваш код и описать проблему, с которой вы столкнулись; кто-то, несомненно, поможет вам сделать следующий шаг.

Отказ от ответственности:

Как указано в начале, я был довольно удивлен, не обнаружив рабочего кода на inte rnet но довольно много сломанных, мой мозг блокировки слишком переполнен? Существует ли простая интерпретация результата inferringMoves(), которая не требует шага смешения, описанного выше? Такое впечатление, что должно быть, документация Apple может быть плохой, но семантика их API обычно хорошая. Так что, может быть, и если это так, я надеюсь, что кто-то отправит его как ответ, и в этот момент я удалю его, даже если он работает.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...