7
$\begingroup$

I need to change the position of a single element in a list. Example: I start with:

{a,b,c,d,e,f}

I want to move the a before the d to get:

{b,c,a,d,e,f}

How would I do this? Thank you!

$\endgroup$
7
$\begingroup$
data = {a, b, c, d, e, f};
Permute[data, {3, 1, 2}]

or

Permute[data, Cycles[{{1, 3, 2}}]]

Both give

{b, c, a, d, e, f}

Edit

It occurred to me that it would be good to be able to move an element to a lower position in the list as well as a higher one. Together the following two functions give both capabilities.

Upward movement -- move an element at position m to position n, where m < n:

moveElementUp[data_List, m_Integer /; m > 0, n__Integer /; n > 0] /; m < n :=
  Permute[data, Join[Range[m - 1], {n}, Range[m, n - 1]]]

moveElementUp[data, 1, 3]
{b, c, a, d, e, f}
moveElementUp[data, 2, 5]
{a, c, d, e, b, f}
moveElementUp[data, 1, 6]
{b, c, d, e, f, a}

Downward movement -- move an element at position m to position n, where m > n:

moveElementDown[data_List, m_Integer /; m > 0, n__Integer /; n > 0] /; m > n :=
  Permute[data, Join[Range[n - 1], 1 + Range[n, m - 1], {n}]]

moveElementDown[data, 3, 1]
{c, a, b, d, e, f}
moveElementDown[data, 5, 3]
{a, b, e, c, d, f}
moveElementDown[data, 6, 1]
{f, a, b, c, d, e}

Note

Although I found it interesting to attack this problem with permutations, I suspect there is a better solution.

$\endgroup$
4
$\begingroup$

Probably not the most elegant way but...

swap[list_, from_, to_] := 
 Module[{ele = list[[from]], modlist = list}, 
  modlist[[from]] = Sequence[]; modlist = Insert[modlist, ele, to];
  modlist]

swap[list, 1, 3]

{b, c, a, d, e, f}

If you always want the moving element in front of d...

swap[list, 1, FirstPosition[list, d] - 1]

Note, in 10.2 you can use Nothing instead of Sequence[].

Or, if you insist on using patterns...

from = 1;
to = 3;
list /. {a___, list[[from]], b___, list[[to + 1]], c___} :> {a, b, 
 list[[from]], list[[to + 1]], c}
$\endgroup$
4
$\begingroup$

The following answer is effectively equivalent to m_goldberg's answer, except that the distinction between the two directions of movement has been eliminated:

moveElement[l_List, m_Integer?Positive, n_Integer?Positive] :=
   Module[{idx}, 
                idx = Range @@ Sort[{m, n}];
                ReplacePart[l, Thread[idx -> l[[RotateLeft[idx, Sign[n - m]]]]]]]

Both moveElementUp[] and moveElementDown[] in his answer can be replaced with this unified function.

$\endgroup$
1
$\begingroup$

Or you could just

moveElement[l_, from_, to_] := Insert[Delete[l, from], l[[from]], to]

Works up and down.

$\endgroup$
0
$\begingroup$
ClearAll[move]
move[lst_, from_, to_] :=  Module[{a = lst, p = Sort[{from, to}]}, 
  a[[p[[1]] ;; p[[2]]]] =  RotateRight[a[[p[[1]] ;; p[[2]]]], to - from]; a]

move[{a, b, c, d, e, f}, 1, 3]

{b, c, a, d, e, f}

move[{a, b, c, d, e, f}, 3, 1]

{c, a, b, d, e, f}

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.