4
$\begingroup$

This is a question about ReplacePart but if there's a better that's great.

If I have a list

a= {1,2,3,4,5} 

and I want to replace elements 1,3,5 with elements a,b,c from list {a,b,c}, can I use ReplaceParts to do this in one step?

I have only been able to do this replacing one element at a time.

Thanks.

$\endgroup$
10
  • 1
    $\begingroup$ list /. {1 -> a, 3 -> b, 5 -> c} $\endgroup$
    – Hubble07
    Dec 31, 2014 at 9:18
  • $\begingroup$ @Hubble07: You are saying that if the first list contains 1000 elements and the second list contains 500 that I would have to type 1->a, etc. 500 times? $\endgroup$
    – daniel
    Dec 31, 2014 at 9:45
  • $\begingroup$ Isn't there some way to use a list of indices and replacement elements and do this all at once? $\endgroup$
    – daniel
    Dec 31, 2014 at 9:54
  • 4
    $\begingroup$ you have names conflict, a is a list and an element of the last list. p.s. does this work for you: list /. Thread[{1,2,3}->{a,b,c}]? $\endgroup$
    – Kuba
    Dec 31, 2014 at 9:57
  • 1
    $\begingroup$ for this specific case you can use a[[;; ;; 2]]= {aa,b,c}. I have changed a to aa because of name conflict as kuba mentioned. $\endgroup$ Dec 31, 2014 at 10:09

4 Answers 4

6
$\begingroup$

I would suggest not using ReplacePart but Part assignment or Riffle instead.

Three functions to compare:

repOdd1[old_, new_] := ReplacePart[old, Thread[Range[1, Length@old, 2] -> new]]

repOdd2[old_, new_] := Module[{x = old}, x[[;; ;; 2]] = new; x]

repOdd3[old_, new_] := Riffle[new, old[[2 ;; ;; 2]]]

Test:

a = Range@9;
b = {q, r, s, t, u};

repOdd1[a, b]
repOdd2[a, b]
repOdd3[a, b]
{q, 2, r, 4, s, 6, t, 8, u}

{q, 2, r, 4, s, 6, t, 8, u}

{q, 2, r, 4, s, 6, t, 8, u}

Performance:

a = Range@999999;
b = Range[1000001, 1500000];

repOdd1[a, b] // AbsoluteTiming // First
repOdd2[a, b] // AbsoluteTiming // First
repOdd3[a, b] // AbsoluteTiming // First
1.052060

0.002000

0.008001

Both Part and Riffle are orders of magnitude faster than ReplacePart. Part assignment is a bit more verbose than Riffle if we include Module but also faster and applicable for in-place modification should that be desired.

Part also works for an arbitrary index list, not only an evenly spaced Span:

(* in-place modification in this example *)

a = Range@9;
b = {q, r, s, t, u};
a[[{1, 2, 9, 7, 5}]] = b;
a
{q, r, 3, 4, u, 6, t, 8, s}

I am a fan of using Part for many operations: Elegant operations on matrix rows and columns

$\endgroup$
4
  • $\begingroup$ Kuba has not posted his/her answer--what do you think of that suggestion, out of curiosity? $\endgroup$
    – daniel
    Dec 31, 2014 at 11:09
  • $\begingroup$ @daniel By my interpretation of the question that is not a solution. I am assuming that the list elements 1, 2, 3, are arbitrary, not always natural numbers 1..n. $\endgroup$
    – Mr.Wizard
    Dec 31, 2014 at 11:11
  • $\begingroup$ With that in mind I will accept yours as the more general solution, although because my lists are almost always of numbers Kuba's response was helpful. $\endgroup$
    – daniel
    Dec 31, 2014 at 11:16
  • 1
    $\begingroup$ @daniel If you wish to replace by index it will be faster to do that using Part assignment. However if you wish to replace elements by pattern, which is what Kuba's code does, it is not applicable. These are two different operations with only one intersection: the case where the starting list is Range[ n ]. $\endgroup$
    – Mr.Wizard
    Dec 31, 2014 at 11:20
8
$\begingroup$

What about

ReplacePart[{1, 2, 3, 4, 5}, Thread[{1, 3, 5} -> {a, b, c}]]

or in general

replaceParts[original_, positions_, replacements_] := ReplacePart[
    original,
    Thread[positions -> replacements]
]
$\endgroup$
3
  • $\begingroup$ Assuming it works, doesn't add a step? Basically in Kuba's note it's just "Thread." Very economical. But if it works, fine.+1 $\endgroup$
    – daniel
    Dec 31, 2014 at 10:44
  • 1
    $\begingroup$ No. There are two steps in both my example is: ReplacePart[{1, 2, 3, 4, 5}, Thread[{1, 3, 5} -> {a, b, c}]], while Kuba's is ReplaceAll[{1, 2, 3, 4, 5}, Thread[{1, 3, 5} -> {a, b, c}]]. Secondly Kuba's only works if the original list is a Range, mine works with any list. $\endgroup$
    – Carlo
    Dec 31, 2014 at 16:32
  • $\begingroup$ Inner[Rule,{1,3,5},{a,b,c}] should be faster than Thread[{1, 3, 5} -> {a, b, c}], if speed is a consideration. $\endgroup$
    – Soldalma
    Sep 28, 2016 at 21:00
5
$\begingroup$

I prefer other answers (particularly Part if the application permits it), but I will take this opportunity to mention the undocumented four-argument form of ReplacePart:

ReplacePart[{1, 2, 3, 4, 5}, {a, b, c}, {{1}, {3}, {5}} , {{1}, {2}, {3}}]
(* {a,2,b,4,c} *)

This syntax says to replace parts 1, 3, and 5 of {1, 2, 3, 4, 5} with parts 1, 2, and 3 of {a, b, c}. This syntax has been supported for a very long time, but it is undocumented so I suppose it could disappear some day.

Incidentally, and not relevant to the present question, there is also an undocumented three-argument form:

ReplacePart[{1, 2, 3, 4, 5}, {a, b, c}, {{1}, {3}, {5}}]
(* {{a,b,c},2,{a,b,c},4,{a,b,c}} *)

This form says to replace parts 1, 3, and 5 of {1, 2, 3, 4, 5} with the value {a, b, c}.

$\endgroup$
3
  • $\begingroup$ I almost posted this myself but I could not see how it simplified the problem so I did not. You were probably the one I learned it from. Is this posted elsewhere on site? $\endgroup$
    – Mr.Wizard
    Dec 31, 2014 at 23:57
  • $\begingroup$ @Mr.Wizard I posted here because it is vaguely relevant and I haven't seen it mentioned elsewhere on the site. There are more posts that use ReplacePart than I care to review, so it might be out there somewhere. I'm pretty sure I've discussed it before somewhere in the StackExchange universe, but it would have been in chat or a comment. $\endgroup$
    – WReach
    Jan 1, 2015 at 0:46
  • $\begingroup$ One reference: (17344). Anyway +1 for taking the time to remind us of this nugget even it if doesn't fit perfectly. $\endgroup$
    – Mr.Wizard
    Jan 1, 2015 at 6:04
2
$\begingroup$
ReplacePart[{1, 2, 3, 4, 5}, {i_?OddQ} :> {a, b, c}[[(i + 1)/2]]]

{a, 2, b, 4, c}

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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