# Separate or order the positive and negative terms of an expression

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 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.

Perhaps something like:

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


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

OP requested a function:

posneg[expr_] := Values @ GroupBy[
Replace[expr,
{
a_Plus :> List@@a,
a_ :> {a}
}
],
InternalSyntacticNegativeQ,
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}
}
],
InternalSyntacticNegativeQ,
Total @* Rest
]


Examples:

posneg[-x]
posneg[x]


{-x, 0}

{0, x}

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

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

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

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?