Here is what I have done.
Input
DeleteCases[{{x -> a}, {x -> b}, {x -> c, x -> d}}, Rule, {2}]
Output
{{x -> a}, {x -> b}, {x -> c, x -> d}}
Why is it not {{x, a}, {x, b}, {{x, c}, {x, d}}}
?
DeleteCases
does not by default operate on heads. You can set the Heads
option to True
to change that.
DeleteCases[{{x -> a}, {x -> b}, {x -> c, x -> d}}, Rule, {3}, Heads -> True]
{{x, a}, {x, b}, {x, c, x, d}}
Note that the last term has become {x, c, x, d}
which is not quite what you expected, but it is logically consistent if we expect {x -> a}
to become {x, a}
.
A simpler path to the same output in this case is:
{{x -> a}, {x -> b}, {x -> c, x -> d}} /. Rule -> Sequence
{{x, a}, {x, b}, {x, c, x, d}}
Your expected output can be had from:
{{x -> a}, {x -> b}, {x -> c, x -> d}} /. Rule -> List /. {x_List} :> x
{{x, a}, {x, b}, {{x, c}, {x, d}}}
Recommended reading:
Apply
to 2nd levelspec?
$\endgroup$
Apply[Sequence, {{x -> a}, {x -> b}, {x -> c, x -> d}}, {2}]
But understand that Sequence
must evaluate, so this is not directly deleting the head. See the "Recommended reading" link for details.
$\endgroup$
Commented
Feb 17, 2020 at 11:55
Replacing heads is generically supported by Apply (@@ / @@@)
. So a functional way may look like this:
rules = {{x -> a}, {x -> b}, {x -> c, x -> d}};
If[Length[#] == 1, Flatten[#], Identity[#]] & /@ Apply[List, rules, {-2}]
{{x, a}, {x, b}, {{x, c}, {x, d}}}
Or
If[Length[#] == 1, Sequence @@@ #, List @@@ #] & /@ rules
returns the same result.
rules = {{x -> a}, {x -> b}, {x -> c, x -> d}};
rules /. x : {_Rule, __} :> List @@@ x /. Rule :> Splice @* List
{{x, a}, {x, b}, {{x, c}, {x, d}}}
rules = {{x -> a}, {x -> b}, {x -> c, x -> d}};
Using Delete
:
f = Function[s, If[Length@s == 1, List@Delete[First@s, 0],
Map[List@*Delete[0]]@s]];
f /@ rules
{{x, a}, {x, b}, {{x, c}, {x, d}}}
{{x -> a}, {x -> b}, {x -> c, x -> d}} /. (x_ -> a_) :> {x, a} /. {{a__}} :> {a}
also works. $\endgroup$