6
$\begingroup$

I can convert an expression with the head of Times,for example, 12*12.5*13*13.5*14*14.5 to {12, 12.5, 13, 13.5, 14, 14.5} by using the code below:

ReleaseHold[HoldForm[12*12.5*13*13.5*14*14.5] /. Times -> List]

I have a list which contains a lot of such expressions,here is an example:

listSample={12*12.5*13*13.5*14*14.5, 12*12.5*13*13.5*14*14.5,12*12.5*13*13.5*14*14.5, 12*12.5*13*13.5*14*14.5,12*12.5*13*13.5*14*14.5,12*12.5*13*13.5*14*14.5}

I still want to convert all the heads Times to List,but I failed when tried to Map HoldForm to each listItem,because it alway evaluates first. Here is my code:

ReleaseHold[HoldForm[#] /. Times -> List]&/@listSample

I want to get this result:

{{12, 12.5, 13, 13.5, 14, 14.5},{12, 12.5, 13, 13.5, 14, 14.5},{12, 12.5, 13, 13.5, 14, 14.5},{12, 12.5, 13, 13.5, 14, 14.5},{12, 12.5, 13, 13.5, 14, 14.5},{12, 12.5, 13, 13.5, 14, 14.5}}

$\endgroup$

4 Answers 4

11
$\begingroup$

The listSample containing the lists of multiplications must at all times remain wrapped in something that prevents it from being evaluated. So even the mere input line with which you define listSample is not going to work.

When you Map a function onto listSample, the latter isn't wrapped the way it should be, so it gets evaluated. You can't use Map directly on things that you would like to keep unevaluated. Fortunately, you don't need Map in this case since you only want to replace Times by List.

So I'd suggest the following definition which makes the process re-useable:

SetAttributes[removeTimes, HoldAll]; 
removeTimes[list_] := ReleaseHold[Hold[list] /. Times -> List]

Now you can take your example list literally and wrap it in the above function:

removeTimes[
 {12*12.5*13*13.5*14*14.5, 12*12.5*13*13.5*14*14.5, 
  12*12.5*13*13.5*14*14.5, 12*12.5*13*13.5*14*14.5, 
  12*12.5*13*13.5*14*14.5, 12*12.5*13*13.5*14*14.5}]

{{12, 12.5, 13, 13.5, 14, 14.5}, {12, 12.5, 13, 13.5, 14, 14.5}, {12, 12.5, 13, 13.5, 14, 14.5}, {12, 12.5, 13, 13.5, 14, 14.5}, {12, 12.5, 13, 13.5, 14, 14.5}, {12, 12.5, 13, 13.5, 14, 14.5}}

$\endgroup$
1
  • 1
    $\begingroup$ Very useful, for instance if one does copy+paste of a row with numbers from Excel into Mathematica. $\endgroup$ Jul 3, 2012 at 7:48
9
$\begingroup$
data=HoldForm@{12*12.5*13*13.5*14*14.5, 12*12.5*13*13.5*14*14.5,12*12.5*13*13.5*14*14.5, 12*12.5*13*13.5*14*14.5, 2*12.5*13*13.5*14*14.5, 12*12.5*13*13.5*14*14.5};
data/.Times->List // ReleaseHold

gives

{{12, 12.5`, 13, 13.5`, 14, 14.5`}, {12, 12.5`, 13, 13.5`, 14, 14.5`}, 
 {12, 12.5`, 13, 13.5`, 14, 14.5`}, {12, 12.5`, 13, 13.5`,14, 14.5`},
 {12, 12.5`, 13, 13.5`, 14, 14.5`}, {12, 12.5`, 13, 13.5`, 14, 14.5`}}

EDIT: An alternative:

timesToList = Function[{list}, Unevaluated[list] /. Times -> List, HoldAll]
timesToList[{12*12.5*13*13.5*14*14.5, 12*12.5*13*13.5*14*14.5}]
(* ==> {{12, 12.5, 13, 13.5, 14, 14.5}, {12, 12.5, 13, 13.5, 14, 14.5}} *)
$\endgroup$
1
  • $\begingroup$ wow,your code is concise,+1 $\endgroup$ Jul 3, 2012 at 6:19
8
$\begingroup$

The value assigned listSample must be held unevaluated by some means or manipulation is not possible (as there is no Times present). There are several options for this:

  1. Hold

  2. Unevaluated

  3. SetDelayed (:=)

Of these SetDelayed is the most concise, so I will use that:

listSample := {12*12.5*13*13.5*14*14.5, 12*12.5*13*13.5*14*14.5};

Normally this is fully evaluated as soon as you call listSample:

listSample
{5.34398*10^6, 5.34398*10^6}

It is nevertheless stored internally in the unevaluated form. Because of this we can use Block to temporarily change the meaning of Times to List while this evaluation is taking place:

Block[{Times = List}, listSample]
{{12, 12.5, 13, 13.5, 14, 14.5},
 {12, 12.5, 13, 13.5, 14, 14.5}}

You could also access the unevaluated data with OwnValues or with my step evaluation function which I wrote for this purpose.

step[listSample] /. Times -> List // ReleaseHold

This approach would be useful if you needed to do a more complex replacement than you could do with Block, as would Hold or Unevaluated.


Also consider this:

Unevaluated[12*12.5*13*13.5*14*14.5] /. Times -> List
{12, 12.5, 13, 13.5, 14, 14.5}

Notice that no ReleaseHold is needed in this case as Unevaluated momentarily holds its argument, unlike Hold which does so until released.

$\endgroup$
6
  • $\begingroup$ When should we use Unevaluated as opposed to Hold? $\endgroup$ Jul 3, 2012 at 6:52
  • $\begingroup$ @Michael specific to this application, or generally? $\endgroup$
    – Mr.Wizard
    Jul 3, 2012 at 6:53
  • $\begingroup$ Generally. I know that Unevaluated dissolves after we pass it through a function, but are there other considerations to keep in mind? $\endgroup$ Jul 3, 2012 at 6:55
  • $\begingroup$ I am just wondering if you have a rule of thumb to recognize when to use Hold as opposed to Unevaluated. $\endgroup$ Jul 3, 2012 at 6:59
  • $\begingroup$ @Michael basically what you just outlined: use Unevaluated when you want it to "dissolve" after one use, otherwise use Hold. $\endgroup$
    – Mr.Wizard
    Jul 3, 2012 at 7:03
4
$\begingroup$

Given the way you defined listSample, Mathematica evaluates the RHS before setting the value. To understand why this is the case, you may want to read the documentation for the standard evaluation procedure.

In[21]:= listSample
Out[21]= {5.34398*10^6,5.34398*10^6,5.34398*10^6,5.34398*10^6,5.34398*10^6,5.34398*10^6}

Before we can manipulate this list of products, we need to make sure that the RHS is not evaluated. Strictly speaking, Hold as opposed to HoldForm suffices as do not need pretty-printing.

In[22]:= listSample2=Hold@{12*12.5*13*13.5*14*14.5,12*12.5*13*13.5*14*14.5,12*12.5*13*13.5*14*14.5,12*12.5*13*13.5*14*14.5,12*12.5*13*13.5*14*14.5,12*12.5*13*13.5*14*14.5}
Out[22]= Hold[{12 12.5 13 13.5 14 14.5,12 12.5 13 13.5 14 14.5,12 12.5 13 13.5 14 14.5,12 12.5 13 13.5 14 14.5,12 12.5 13 13.5 14 14.5,12 12.5 13 13.5 14 14.5}]

Before I do any sort of manipulation, I find it useful to look at its FullForm:

In[23]:= FullForm@listSample2
Out[23]//FullForm= Hold[List[Times[12,12.5`,13,13.5`,14,14.5`],Times[12,12.5`,13,13.5`,14,14.5`],Times[12,12.5`,13,13.5`,14,14.5`],Times[12,12.5`,13,13.5`,14,14.5`],Times[12,12.5`,13,13.5`,14,14.5`],Times[12,12.5`,13,13.5`,14,14.5`]]]

Another useful representation is TreeForm:

In[24]:= TreeForm@listSample2

TreeForm of listSample2

Either way, we see that the heads Times we want to replace are all at level {2}. Apply is the built-in function which replaces head, so we can use

In[25]:= ReleaseHold@Apply[List,listSample2,{2}]
Out[25]= {{12,12.5,13,13.5,14,14.5},{12,12.5,13,13.5,14,14.5},{12,12.5,13,13.5,14,14.5},{12,12.5,13,13.5,14,14.5},{12,12.5,13,13.5,14,14.5},{12,12.5,13,13.5,14,14.5}}
$\endgroup$

Your Answer

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

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