9
$\begingroup$

I'm new in Mathematica software, and I need help with a simple exercise.

Given the list

list = {x, 3.2, y, 1, 2.679, 3, z, 4, -7.9};

I need to make some rules to generate a new list with only three elements.

  • first element is the product of its symbols
  • second element the product of its integers
  • third element the product of its real numbers

Thus

newlist = {x y z, 12, -67.72512}  

I hope you can help me.

$\endgroup$
9
$\begingroup$

Using rules for this task may be not very efficient, but here is a rule-based solution:

list /. {
    {List -> Times, _Real   -> 1, _Integer -> 1},
    {List -> Times, _Symbol -> 1, _Real    -> 1}, 
    {List -> Times, _Symbol -> 1, _Integer -> 1}
    }

{x y z, 12, -67.7251}

$\endgroup$
16
$\begingroup$

You can use GroupBy in several ways:

GroupBy[list, Head, Apply[Times]] /@ {Symbol, Integer, Real}

{x y z, 12, -67.7251}

or using a combination of GroupBy andLookup (thanks: CarlWoll):

Lookup[{Symbol, Integer, Real}] @ GroupBy[list, Head, Apply[Times]] 

same result

RotateRight @ Values @ GroupBy[SortBy[Head] @ list, Head, Apply[Times]] 

same result

Alternatively, you can use GatherBy:

RotateRight[Times @@@ GatherBy[SortBy[Head] @ list, Head]]

{x y z, 12, -67.7251}

Also, Replace:

Times @@@ Replace[list, {Except @ Blank @ # -> 1} & /@ {Symbol, Integer, Real}, {1}]

and DeleteCases:

Times @@@ (DeleteCases[list, Except@Blank@#] & /@ {Symbol, Integer, Real})
$\endgroup$
  • 1
    $\begingroup$ Lookup would be more idiomatic than mapping: Lookup[GroupBy[list, Head, Apply[Times]], {Symbol, Integer, Real}] $\endgroup$ – Carl Woll May 1 at 19:53
  • $\begingroup$ Thank you @CarlWoll; great point. $\endgroup$ – kglr May 1 at 20:00
  • $\begingroup$ Thank you @Shadowray. Hope the updated version works in general. $\endgroup$ – kglr May 2 at 7:30
  • $\begingroup$ Duplicate symbols may change the head of the product. E.g. {x, x, 1, 2.0} $\endgroup$ – Shadowray May 2 at 7:38
  • $\begingroup$ Whoops!! Thank you again @Shadowray. Fixed now. $\endgroup$ – kglr May 2 at 7:47
12
$\begingroup$

This doesn't involve any rules, but you could use Cases to select the desired types, using Through and Times as needed:

Times@@@Through@{Cases[_Symbol], Cases[_Integer], Cases[_Real]}@list

{x y z, 12, -67.7251}

$\endgroup$
10
$\begingroup$

A way of doing it with Reap and Sow that would work in versions as old as V5, long before newfangled functions like GroupBy were introduced (V.10).

list = {x, 3.2, y, 1, 2.679, 3, z, 4, -7.9};
Reap[
  Switch[#,
     _Symbol, Sow[#, "s"],
     _Integer, Sow[#, "i"],
     _Real, Sow[#, "r"]] & /@ list,
  {"s", "i", "r"}, 
  Times @@ #2&][[-1, All, 1]]
{x y z, 12, -67.7251}
$\endgroup$
  • $\begingroup$ There's no point in using Switch here: Reap[ Sow[#,Head[#]]& /@ list, {Symbol, Integer, Real}, Times@@ #2&][[-1,All,1]] $\endgroup$ – jjagmath May 3 at 14:02
  • $\begingroup$ @jjagmath. Yes, that is a much better way of doing it. I have updated my answer to include your version. Thanks for bringing it to my attention. $\endgroup$ – m_goldberg May 3 at 21:12
8
$\begingroup$

One approach is to select the elements you want, and then mutliply them.

Times @@@ {Select[list, Not[NumberQ[#]] &], 
           Select[list, IntegerQ[#] &], 
           Select[list, NumberQ[#] && Not[IntegerQ[#]] &]}
{x y z, 12, -67.7251}

The first one selects all the symbols (things that are not numbers), the second selects the integers, and the third selects all the reals that are not integers.

$\endgroup$

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.