2
$\begingroup$

I have a list of lists. Minimal example:

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

I want to set the values on position 2 (b and e) to the value of their right neighbour (c and f). I'm sure there must be a solution with Map, similar to this:

Map[#[[2]] = #[[3]] &, lists]

How can I make it work? Thanks!

$\endgroup$
3
  • $\begingroup$ Alternative way: lists.ReplacePart[ IdentityMatrix[Length[First@lists]], {{2, 2} -> 0, {3, 2} -> 1}] $\endgroup$ Aug 26 '15 at 10:32
  • 3
    $\begingroup$ Direct assignment seems simplest for this. lists[[All, 2]] = lists[[All, 3]] $\endgroup$
    – Edmund
    Aug 26 '15 at 10:43
  • $\begingroup$ @Edmund. Good solution, thanks. $\endgroup$
    – keyx
    Aug 26 '15 at 12:41
6
$\begingroup$

Here's a rundown of some methods:

Map[ReplacePart[#, 2 -> #[[3]]] &, lists]
lists[[All, 2]] = lists[[All, 3]] (* Changes `lists` *)
lists /. {a_, _, b_} :> {a, b, b}
lists[[All, {1, 3, 3}]]
MapThread[{#, #3, #3} &, Transpose[lists]]
{#, #3, #3} & @@@ lists

A rather exotic way of addressing a particular part of an expression:

lists = {
   {1, 2, 3, 4, 5, 6, 7},
   {11, 12, 13, 14, 15, 16, 17}
   };
lists /. {s : Repeated[_, {3}], a_, b_, r___} :> {s, a, a, r}

{{1, 2, 3, 4, 4, 6, 7}, {11, 12, 13, 14, 14, 16, 17}}

Of course, all these versions are not equals. The ones relying on pattern matching should be the slowest ones, Part ([[ ]]) should be fast, and so should anonymous functions paired with basic operators (e.g. {#, #3, #3} & @@@ lists.)

$\endgroup$
1
  • $\begingroup$ I tried the first ("ReplacePart[...]") solution, which was fine. But I liked the direkt assignment (solution #2) most. However, thank you very much! $\endgroup$
    – keyx
    Aug 26 '15 at 12:42
3
$\begingroup$

Do you want to swap positions 2 and 3, or just duplicate position 3?

For the first,

#[[{1, 3, 2}]] & /@ lists

returns

(*{{a, c, b}, {d, f, e}}*)

For the second,

#[[{1, 3, 3}]] & /@ lists

returns

(* {{a, c, c}, {d, f, f}} *)
$\endgroup$
2
$\begingroup$

This is a very wrong way to do it, but hopefully it might provide insight. First of all, your approach with slightly corrected syntax:

lists = {{a,b,c},{d,e,f}}
Map[(#[[2]] = #[[3]]) &, lists]

The Set (=) operation has the attribute HoldFirst, therefore it attemps to set the entire {a, b, c}[[2]] construct to c. That doesn't make any sense, so it returns the output of Set (which is the right hands side of the expression) and does nothing else.

Now if we try to override that with an Evaluate:

Map[(Evaluate[#[[2]]] = #[[3]]) &, lists]

then #[[2]] evaluates all the way to b and b gets set to c. This relies on b not having a value prior to the assignment. Otherwise we would get some error such as "could not assign c to raw object 5".

Bear in mind, that this approach does not change the definition of lists. lists is still {{a, b, c}, {d, e, f}}, but after the Map command, b gets an OwnValue of c and e - of f. So in almost every expression using lists it would evaluate all the way to {{a, c, c}, {d, f, f}}. But as soon as you type b=5; e=6, the output of lists will become {{a, 5, c}, {d, 6, f}}.

TL;DR almost certainly, unless you are actually wanting to do a bulk assignment of values to symbols, you should use the solutions in the other answers.

$\endgroup$
1
  • $\begingroup$ This was actually helpful, didn't know many of these things. Thanks! $\endgroup$
    – keyx
    Aug 26 '15 at 12:25

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.