diff --git a/src/app/core/data/array-move-change-analyzer.service.spec.ts b/src/app/core/data/array-move-change-analyzer.service.spec.ts index 5f5388d935..025791d6dc 100644 --- a/src/app/core/data/array-move-change-analyzer.service.spec.ts +++ b/src/app/core/data/array-move-change-analyzer.service.spec.ts @@ -41,21 +41,28 @@ describe('ArrayMoveChangeAnalyzer', () => { ], new MoveTest(0, 3)); testMove([ + { op: 'move', from: '/2', path: '/3' }, { op: 'move', from: '/0', path: '/3' }, - { op: 'move', from: '/2', path: '/1' } ], new MoveTest(0, 3), new MoveTest(1, 2)); testMove([ + { op: 'move', from: '/3', path: '/4' }, { op: 'move', from: '/0', path: '/1' }, - { op: 'move', from: '/3', path: '/4' } ], new MoveTest(0, 1), new MoveTest(3, 4)); testMove([], new MoveTest(0, 4), new MoveTest(4, 0)); testMove([ + { op: 'move', from: '/2', path: '/3' }, { op: 'move', from: '/0', path: '/3' }, - { op: 'move', from: '/2', path: '/1' } ], new MoveTest(0, 4), new MoveTest(1, 3), new MoveTest(2, 4)); + + testMove([ + { op: 'move', from: '/3', path: '/4' }, + { op: 'move', from: '/2', path: '/4' }, + { op: 'move', from: '/1', path: '/3' }, + { op: 'move', from: '/0', path: '/3' }, + ], new MoveTest(4, 1), new MoveTest(4, 2), new MoveTest(0, 3)); }); describe('when some values are undefined (index 2 and 3)', () => { diff --git a/src/app/core/data/array-move-change-analyzer.service.ts b/src/app/core/data/array-move-change-analyzer.service.ts index f6e07608f6..36744e9f96 100644 --- a/src/app/core/data/array-move-change-analyzer.service.ts +++ b/src/app/core/data/array-move-change-analyzer.service.ts @@ -16,22 +16,31 @@ export class ArrayMoveChangeAnalyzer { * @param array2 The custom array to compare with the original */ diff(array1: T[], array2: T[]): MoveOperation[] { - const result = []; - const moved = [...array1]; - array1.forEach((value: T, index: number) => { - if (hasValue(value)) { - const otherIndex = array2.indexOf(value); - const movedIndex = moved.indexOf(value); - if (index !== otherIndex && movedIndex !== otherIndex) { - moveItemInArray(moved, movedIndex, otherIndex); - result.push(Object.assign({ - op: 'move', - from: '/' + movedIndex, - path: '/' + otherIndex - }) as MoveOperation); - } + return this.getMoves(array1, array2).map((move) => Object.assign({ + op: 'move', + from: '/' + move[0], + path: '/' + move[1], + }) as MoveOperation); + } + + /** + * Determine a set of moves required to transform array1 into array2 + * The moves are returned as an array of pairs of numbers where the first number is the original index and the second + * is the new index + * It is assumed the operations are executed in the order they're returned (and not simultaneously) + * @param array1 + * @param array2 + */ + private getMoves(array1: any[], array2: any[]): number[][] { + const moved = [...array2]; + + return array1.reduce((moves, item, index) => { + if (hasValue(item) && item !== moved[index]) { + const last = moved.lastIndexOf(item); + moveItemInArray(moved, last, index); + moves.unshift([index, last]); } - }); - return result; + return moves; + }, []); } }