Who Moved?


The problem originally appeared on K listbox. Also cf. Gene McDonnell's article in Vector Vol. 17 No. 2.

Problem

You're given a vector of unique elements:

  v:10 20 30 40 50 60 70

Some operation has moved a single one of the elements into a new position:

  w:10 20 70 30 40 50 60	/ 70 inserted between 10 and 20

You want a function which returns the index of the repositioned element:

  f[v;w]
2

The element v i has moved to w j, j < i.

Elements at positions < i in v will occupy the same positions in w.
Elements at positions > i and < j will be shifted down by 1.
Elements at positions > j will be shifted up by 1.

If j > i, then reverse the signs.

The function f takes v and w and finds j.

Consider:

10 20 30
10 30 20

Did 20 move + 1, or did 30 move - 1?

Either: let f pick one. Similarly in the case

10 20
20 10

or wherever the move is only one position away:

10 20 30 40 50
10 20 40 30 50

Solutions

  a:10 20 30 40 50
  b:10 40 20 30 50
  c:10 30 40 20 50
  d:10 20 40 30 50
  e:50 10 20 30 40
  f:{d?|/d:_abs(x?/:y)-!#x}
  a f/:(b;c;d;e)
1 3 2 0

If an element has moved, then, if it has moved more than one position, its new position will differ from its old positon by a greater amount than the new position of any other element does from its former position.

If it has moved only one position, then there will be at most two elements whose positions differ from their original positions; in this case, pick either.

Alternatives:

f2:{:[y[d 1]=x[(d:(*|q),*q:&~x=y) 0];d 1;d 0]}
f3:{d@=/(x;y)@'d:(*|:;*:)@\:&~x=y}
f4:{d@=/(x;y)@'d:2#-1!&~x=y}
  a f4/:(b;c;d;e)
1 3 2 0