10
$\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$

7 Answers 7

10
$\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$
17
$\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$
5
  • 1
    $\begingroup$ Lookup would be more idiomatic than mapping: Lookup[GroupBy[list, Head, Apply[Times]], {Symbol, Integer, Real}] $\endgroup$
    – Carl Woll
    Commented May 1, 2019 at 19:53
  • $\begingroup$ Thank you @CarlWoll; great point. $\endgroup$
    – kglr
    Commented May 1, 2019 at 20:00
  • $\begingroup$ Thank you @Shadowray. Hope the updated version works in general. $\endgroup$
    – kglr
    Commented May 2, 2019 at 7:30
  • $\begingroup$ Duplicate symbols may change the head of the product. E.g. {x, x, 1, 2.0} $\endgroup$
    – Ray Shadow
    Commented May 2, 2019 at 7:38
  • $\begingroup$ Whoops!! Thank you again @Shadowray. Fixed now. $\endgroup$
    – kglr
    Commented May 2, 2019 at 7:47
13
$\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$
11
$\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$
2
  • $\begingroup$ There's no point in using Switch here: Reap[ Sow[#,Head[#]]& /@ list, {Symbol, Integer, Real}, Times@@ #2&][[-1,All,1]] $\endgroup$
    – jjagmath
    Commented May 3, 2019 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
    Commented May 3, 2019 at 21:12
10
$\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$
1
$\begingroup$
list = {x, 3.2, y, 1, 2.679, 3, z, 4, -7.9};

Times @@ Cases[list, #] & /@ {_Symbol, _Integer, _Real}

{x y z, 12, -67.7251}

If the sort - order of the result doesn' t matter and the list doesn' t contain "alien" elements:

Times @@@ GatherBy[list, Head]

{x y z, -67.7251, 12}

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

Using SortBy and SplitBy:

ReverseSort@(Times @@@ SplitBy[SortBy[#, Head], Head]) &@list

(*{x y z, 12, -67.7251}*)
$\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.