6

I have two lists, that looks like below

list1 = {a, x, b, x, x, c};
list2 = {2, 3, 4, 5, 6, 7};

Any time there is an x in the first list (list1), I want to replace it with the corresponding element in the second list (list2).

Any suggestions on nice ways to go about doing this?


I realize this should be simple with a loop (get the length of the lists, let the loop iterator be the index, and just compare and replace element by element)

However, I believe its usually better to use Map, MapThread, or take advantage of Listable attributes. I don't see how I can do so here, but feel there might be a simple way?

Perhaps something with MapIndexed as mentioned here


Edit: The best way I can come up with is below. It still requires using a local environment Module though, which I feel like might be avoided by a better approach.

Module[{rules, keys},
 keys = Flatten@Position[{a, x, b, x, x, c}, x];
 rules = AssociationThread[keys -> {2, 3, 4, 5, 6, 7}[[keys]]];
 ReplacePart[{a, x, b, x, x, c}, rules]
 ]

Edit 2: I have realized my question is perhaps a duplicate of this old question, but answers have just been posted here so I will not delete my question. Sorry for the confusion and mistake.

user106860
  • 829
  • 4
  • 10

4 Answers4

5
MapIndexed[If[# === x, list2[[#2[[1]]]], #] &, list1]
 {a, 3, b, 5, 6, c}

Alternatively,

xpos = Flatten @ Position[list1, x];
res = list1; res[[xpos]] = list2[[xpos]];  res
 {a, 3, b, 5, 6, c}

and

(Transpose[{list1, list2}] /. {x, i_} :> {i, i})[[All, 1]]
{a, 3, b, 5, 6, c}

and alternative way to use ReplacePart:

xpos = Flatten @ Position[list1, x];
ReplacePart[list1, Thread[xpos -> list2[[xpos]]]]
{a, 3, b, 5, 6, c}
kglr
  • 394,356
  • 18
  • 477
  • 896
  • I like the first one since it does not require defining a new (possibly local) variable. The reason you have #2[[1]] though, is because I think MapIndexed uses the index in brackets as the second argument, yes? (i.e. it uses {i} instead of i). I see you have also edited to add more solutions, some of which also may not need local variables. Thank you. – user106860 May 30 '21 at 21:48
  • 1
    @user106860, you are right; the argument #2 refers to a list in MapIndexed. – kglr May 30 '21 at 21:49
4
list1 = {a, x, b, x, x, c};
list2 = {2, 3, 4, 5, 6, 7};

Find the positions of the first list

ix = Position[list1, x]
(* {{2}, {4}, {5}} *)

Replace them in the second list

ReplacePart[list1, Thread[ix -> Extract[list2, ix]]]
(* {a, 3, b, 5, 6, c} *)
mikado
  • 16,741
  • 2
  • 20
  • 54
2
list1 = {a, x, b, x, x, c};
list2 = {2, 3, 4, 5, 6, 7};

Using SubsetMap:

p = Position[list1, x];

vals = Extract[list2, p];

SubsetMap[vals &, list1, p]

({a, 3, b, 5, 6, c})

E. Chan-López
  • 23,117
  • 3
  • 21
  • 44
1
MapThread[If[#1 === x, #2, #1]&, {list1, list2}]

{a, 3, b, 5, 6, c}

eldo
  • 67,911
  • 5
  • 60
  • 168