5
$\begingroup$

I am using Mathematica to manipulate/keep track of a long series of symbol manipulations.

One thing that I would like to do is separate or order the terms of an expression by positive and negative sign.

For example separating enter image description here or something more simple that we can use as an example

b+ c^2 -c^2 +a^4 -c^5

I say order by positive or negative sign as (for my problem) we assume that the constants are all positive.

I looked at this post but I don't know how I can apply this to my problem.

$\endgroup$

3 Answers 3

12
$\begingroup$

Perhaps something like:

Values @ GroupBy[
    List @@ (b+c^2-c^2+a^4-c^5),
    Internal`SyntacticNegativeQ,
    Total
]

{a^4 + b, -c^5}

Addendum

OP requested a function:

posneg[expr_] := Values @ GroupBy[
    Replace[expr,
        {
        a_Plus :> List@@a,
        a_ :> {a}
        }
    ],
    Internal`SyntacticNegativeQ,
    Total
]

A couple examples:

posneg[b+c^2-c^3+a^4-c^5]
posneg[x-2]

{a^4 + b + c^2, -c^3 - c^5}

{-2, x}

Update

A comment requested a version that always returns both the negative and positive parts, padding with 0 if necessary.

One way to do this is to add both a positive and a negative number to the list, and then remove those numbers at the end. Here is a variation that does this:

posneg[expr_]:=Values@GroupBy[
    Replace[expr,
        {
        a_Plus:>Join[{-1,1}, List@@a],
        a_:>{-1, 1, a}
        }
    ],
    Internal`SyntacticNegativeQ,
    Total @* Rest
]

Examples:

posneg[-x]
posneg[x]

{-x, 0}

{0, x}

$\endgroup$
6
  • $\begingroup$ Looks great. Can it be written so that it can be defined once and used as a function. $\endgroup$ Commented Jan 17, 2018 at 23:23
  • 1
    $\begingroup$ Did you want List @@ expr instead of List @@ Flatten[{expr}]? $\endgroup$ Commented Jan 18, 2018 at 3:08
  • $\begingroup$ @MichaelE2 I wanted the function to work for both Plus and non-Plus objects. Thanks for catching the error. $\endgroup$ Commented Jan 18, 2018 at 3:39
  • $\begingroup$ @CarlWoll Thanks just what I was looking for. $\endgroup$ Commented Jan 18, 2018 at 16:01
  • 1
    $\begingroup$ @Balazs Please see update. $\endgroup$ Commented May 1, 2018 at 17:25
6
$\begingroup$

perhaps

ClearAll[order]
order[Times[x_?Negative, _]| _?Negative] := -1
order[_] := 1;

GatherBy[List@@(b + c^2 - c^3 + a^6 - c^5), order]

{{a^6, b, c^2}, {-c^3, -c^5}}

Values @ GroupBy[List @@ (b + c^2 - c^3 + a^6 - c^5), order]

{{a^6, b, c^2}, {-c^3, -c^5}}

Values @ GroupBy[List @@ (b + c^2 - c^3 + a^6 - c^5), order, Total]

    {a^6 + b + c^2, -c^3 - c^5}

Values @ Merge[Identity][order[#] -> # & /@ (List @@ (b + c^2 - c^3 + a^6 - c^5))]

{{a^6, b, c^2}, {-c^3, -c^5}}

Values @ Merge[Total][order[#] -> # & /@ (List @@ (b + c^2 - c^3 + a^6 - c^5))]

{a^6 + b + c^2, -c^3 - c^5}

SortBy[Inactivate[b + c^2 - c^3 + a^6 - c^5, Plus], order]

-c^3 + -c^5 + a^6 + b + c^2

$\endgroup$
3
  • $\begingroup$ Can you tell me what the second thing does? $\endgroup$ Commented Jan 17, 2018 at 23:21
  • $\begingroup$ It groups the elements of the set according to the condition order, as previously defined. $\endgroup$ Commented Jan 17, 2018 at 23:24
  • $\begingroup$ Thank you @David. AzJ, wrapped it with Values now to get a list of groups rather than an Association. $\endgroup$ Commented Jan 17, 2018 at 23:45
3
$\begingroup$

How about this?

Definitions:

sum = b + c^2 - c^2 + a^4 - c^5;

signList = List[];

posList = List[];

negList = List[];

Function to find the sign of the term by dividing the term by the absolute value of the term, in the list on the end you can put the assumptions on the constants.

sign[i_, expr_] := 
 Refine[expr[[i]]/Abs[expr[[i]]], {a > 0, b > 0, c > 0}]

Make a list where you find all the signs. For-loop going through all the terms, using the fn sign to find the sign and put it in signList.

findOrder[expr_] := For[i = 1, i < (Length[expr] + 1), i++, signList = Append[signList, N[sign[i, expr]]]]

Then order the terms in two separate lists, depending on their sign.

orderTerms[expr_] := For[i = 1, i < (Length[expr] + 1), i++, If[signList[[i]] > 0, posList = Append[posList, expr[[i]]], negList = Append[negList, expr[[i]]]]]

So for this example:

findOrder[sum]

orderTerms[sum]

posList

{a^4, b}

negList

{-c^5}

Is this what you wanted?

$\endgroup$

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.