3
$\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$
9
$\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$
  • $\begingroup$ Looks great. Can it be written so that it can be defined once and used as a function. $\endgroup$ – AzJ Jan 17 '18 at 23:23
  • 1
    $\begingroup$ Did you want List @@ expr instead of List @@ Flatten[{expr}]? $\endgroup$ – Michael E2 Jan 18 '18 at 3:08
  • $\begingroup$ @MichaelE2 I wanted the function to work for both Plus and non-Plus objects. Thanks for catching the error. $\endgroup$ – Carl Woll Jan 18 '18 at 3:39
  • $\begingroup$ @CarlWoll Thanks just what I was looking for. $\endgroup$ – AzJ Jan 18 '18 at 16:01
  • 1
    $\begingroup$ @Balazs Please see update. $\endgroup$ – Carl Woll May 1 '18 at 17:25
5
$\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$
  • $\begingroup$ Can you tell me what the second thing does? $\endgroup$ – AzJ Jan 17 '18 at 23:21
  • $\begingroup$ It groups the elements of the set according to the condition order, as previously defined. $\endgroup$ – David G. Stork Jan 17 '18 at 23:24
  • $\begingroup$ Thank you @David. AzJ, wrapped it with Values now to get a list of groups rather than an Association. $\endgroup$ – kglr Jan 17 '18 at 23:45
2
$\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$

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.