12
$\begingroup$

Is there some equivalence of MapIndexed for rules?

Consider a substitution on

3 a + 4 b + 21 c + ....

The first integer I want to replace by 1, the second integer by 4, and the i'th integer by i^2.

1 a + 4 b + 9 c  + ....

How would you do that? I imagine some kind of indexed replacement would be useful.

Addition:I would like to use it to replace expressions like f[a]@f[b]@f[c]@...@f[X] with f[1]@f[2]@f[3]@...@f[n]

$\endgroup$
0

9 Answers 9

12
$\begingroup$

Here is a simple approach,

index = 0
1 a + 2 b + 4 c + 10 f /.  b_?IntegerQ :> (++index)^2

Unlikely to do as you expect, but I'll mention it as it does work in some situations.

Note for one thing you lose the '1' as it is simplified out before substitution

$\endgroup$
1
  • 2
    $\begingroup$ You beat me by four seconds. :-) $\endgroup$
    – Mr.Wizard
    Sep 24, 2012 at 17:52
8
$\begingroup$

If we assume that the integers that you wish to replace are on the first level as in the example, then a good equivalent for MapIndexed is... MapIndexed! The second argument does not need to be a list:

$eqn = 3 a + 4 b + 21 c;

MapIndexed[#1 /. _Integer :> #2[[1]]^2 &, $eqn]

(* a + 4 b + 9 c *)
$\endgroup$
7
$\begingroup$

Here's an approach that uses a more explicit rule replacement:

MapIndexed[{##} /.
   {coeff_ sym_ | sym_, {index_}} :> index^2 sym &,
 expr]
$\endgroup$
6
$\begingroup$

Though it is not purely functional I often find it easiest to simply use a temporary variable for incrementing in a replacement:

Module[{i = 1},
 3 a + 4 b + 21 c /. n_Integer :> i++^2
]
a + 4 b + 9 c

A couple of answers are assuming that you want to increment the counter for each object at level one, rather than for each appearance of an integer. This is an important distinction. Consider:

expr = 3 a^2 + b + 21 c;

Module[{i = 1}, expr /. n_Integer :> i++^2]
a^4 + b + 9 c

If instead you prefer operate on coefficients including the implicit 1 for b you might consider tools like CoefficientRules for your manipulation:

CoefficientRules[expr]

MapIndexed[# -> #2[[1]]^2 &, %[[All, 1]]]

FromCoefficientRules[%, Variables@expr]
{{2, 0, 0} -> 3, {0, 1, 0} -> 1, {0, 0, 1} -> 21}

{{2, 0, 0} -> 1, {0, 1, 0} -> 4, {0, 0, 1} -> 9}

a^2 + 4 b + 9 c
$\endgroup$
1
  • $\begingroup$ I was trying to fix the issue with the lack of an integer. The first attempt, while not fixing it does give an amusing result: Module[{i = 1}, expr /. (n_.) s_Symbol :> i++^2 s]. Removing Symbol does not do the job, either, but the result isn't nearly as cool. I need to play with it to see if it is doable with replacement rules. In the meantime, the first result is infinitely more opaque if you forget the s on the RHS. $\endgroup$
    – rcollyer
    Sep 24, 2012 at 20:59
4
$\begingroup$

Ah well, watch dis (which will end in tears if you do not provide the structure mentioned by @R.M):

i = 1;
3 a + 4 b + 21 c + 30 d + 15 e /. Times[a_, b_] :> (i++)^2 b
a + 4 b + 9 c + 16 d + 25 e

Regarding your additional request:

i = 1;
f[a]@f[b]@f[c]@f[d] /. f[a_] :> f[i++]
f[1][f[2][f[3][f[4]]]]
$\endgroup$
0
3
$\begingroup$

Assuming your expression is of the form given in the question and that it is ordered in the sense of OrderedQ, then a simple way to replace the numbers would be:

Dot[Range[Length@#]^2, #] &@Last@GatherBy[Level[3 a + 4 b + 21 c, {-1}], Head]
(* a + 4 b + 9 c *)

To break it down further, Level[3 a + 4 b + 21 c, {-1}] gives you the leaves of the expression (or loosely speaking, the individual components sans the head), which is {3, a, 4, b, 21, c}. Then it is collected according to their heads using GatherBy, and Integer comes before Symbol. Finally, the integers are discarded and replaced with the square of the indices and then the expression is reconstructed.

$\endgroup$
2
$\begingroup$
Range[ Length @ #]^2 . Last /@ List @@ # &[3 a + 4 b + 21 c + 30 d + 15 e]
a + 4 b + 9 c + 16 d + 25 e

or

List @@ #[[All, 2]].(Range @ Length @ #)^2 & [ 3 a + 4 b + 21 c + 30 d + 15 e]
$\endgroup$
1
$\begingroup$

For your first request, we can use ReplacePart as follows:

expr = 3  a + 4  b + 21  c + 30  d + 15  e;

ReplacePart[#, Thread[# -> Range@Length@#^2] &@Position[#, n_Integer]] &@expr

(*a + 4 b + 9 c + 16 d + 25 e*)

For your additional request, we can use Cases:

expr = f[a]@f[b]@f[c]@f[d];

r = Thread[# -> Range@Length@#] &;

expr /. r@Cases[expr, s_Symbol /; s =!= f, ∞, Heads -> True]

(*f[1][f[2][f[3][f[4]]]]*)
$\endgroup$
1
$\begingroup$
expr = 3 a + 4 b + 21 c;

Plus @@ Times @@@ Transpose[{Range @ Length @ expr^2, Cases[expr, _Symbol, {2}]}]

a + 4 b + 9 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.