1
$\begingroup$

As most regular users, I have developed utility functions complementing the Wolfram language for frequent tasks.

In particular, I have variations on Cases (see example definitions below). But I have trouble to add to them the pattern transformation capabilities of Case, such as Cases[ {1,3,5,6}, a:_Integer?EvenQ :> a/2 /; (a>0)] because my current versions rely on Position, not on Cases. I usually can do what I want with my CaseMap function or other classical means at the expense of legibility and maintainability but I am also curious of the right way to construct such a pattern handling syntax.

CaseSort sorts specific elements disseminated in a structure

CaseSort[k_List, p_] := CaseSort[k, p, 1]

CaseSort[k_List, p_, z__] := Module[{kb = k, csz}, MapThread[
(Part[kb, Sequence @@ #2] = #1 ) &, {Sort[
 Extract[k, csz = Position[k, p, z]]], csz}]; kb]

CaseSortBy is a straightforward variation on it

CaseSortBy[k_List, f_, p_] := CaseSortBy[k, f, p, 1]

CaseSortBy[k_List, f_, p_, z__] := Module[{kb = k, csz}, MapThread[
(Part[kb, Sequence @@ #2] = #1 ) &, {SortBy[
 Extract[k, csz = Position[k, p, z]], f], csz}]; kb]

CaseMap is a cousin of MapAt and Replace

CaseMap[f_, k_List, p_] := CaseMap[k, p, 1]

CaseMap[f_, k_List, p_, z__] := Module[{kb = k, csz}, MapThread[
(Part[kb, Sequence @@ #2] = f[#1] ) &, {Extract[k, 
 csz = Position[k, p, z]], csz}]; kb]

CaseMapIndexed allows to have the positional context of the element when modifying it.

CaseMapIndexed[f_, k_List, p_] := CaseMapIndexed[k, p, 1]

CaseMapIndexed[f_, k_List, p_, z__] := Module[{kb = k, csz}, MapThread[
(Part[kb, Sequence @@ #2] = f[#1, #2] ) &, {Extract[k, 
 csz = Position[k, p, z]], csz}]; kb]
$\endgroup$
  • $\begingroup$ So, how about writing another definition, e.g. CaseSort[list_List, r:(_Rule | _RuleDelayed)] := (* stuff *)? $\endgroup$ – J. M. will be back soon May 27 '15 at 9:41
  • 2
    $\begingroup$ Could we start with one example, like CaseSort and with description what would you like to change there, or what is not ok from your point of view? $\endgroup$ – Kuba May 27 '15 at 10:16
  • $\begingroup$ @Guesswhoitis. I have done that, and it works in elementary cases such as CaseSort but I somehow messed up when testing for and manipulating Condition and PatternTest. I will try to come up with a few clear examples of this. $\endgroup$ – ogerard May 28 '15 at 6:56
  • $\begingroup$ @Kuba that's fair. I will soon edit my question. But in the meantime, I think Mr.Wizard pointed out my main trouble: I would like "Indexed" versions of most of these functions, and ideally, I would like something like a IndexedPatternTest which would transmit the position of the matched pattern in the expression being scanned by Cases, Count, or Position, etc. as a second argument. $\endgroup$ – ogerard May 28 '15 at 7:02
1
$\begingroup$

I think you are bumping up against the limitation described here:

I say this because I think you want a combination of Replace and Position in one step, but this is not directly possible. We can still do it in multiple steps however. For simplicity I shall assume any Condition expressions will appear on the left-hand side of the rule. This precludes the lhs :> Module[{vars}, rhs /; test] form which would require additional complication. With limited modification to your original code:

caseSort[k_List, p_] := caseSort[k, p, 1]

caseSort[k_List, rule : (lhs_ -> _) | (lhs_ :> _), z__] :=
 Module[{kb = k, pos = Position[k, lhs, z]},
  MapThread[(Part[kb, Sequence @@ #2] = #1) &,
   {Sort @ Replace[Extract[k, pos], rule, {1}], pos}];
  kb
 ]

Test:

caseSort[Reverse@Range@20, p_?OddQ /; PrimeQ[p] :> Pi*p]
{20, 3 π, 18, 5 π, 16, 15, 14, 7 π, 12, 11 π, 10, 9, 8, 13 π, 6, 17 π, 4, 19 π, 2, 1}

A more radical departure from you code:

caseSort2[k_List, rule : (lhs_ -> rhs_) | (lhs_ :> rhs_), z__: {1}] :=
  Module[{tag, main, cases, i = 1},
    {main, {cases}} = Reap[Replace[k, lhs :> (Sow[rhs]; tag), z]];
    cases = Sort[cases];
    main /. tag :> cases[[i++]]
  ]

I do not claim that either of these functions is robust, e.g. concerning held expressions etc.

$\endgroup$
  • $\begingroup$ Thanks a lot. You are right on one of my motivations. This covers a large part of what I need. I made a prototype with Reap and Sow but it did not take advantage, as yours do, of the fact that the two Replace will change objects in the same order as we preserve the structure. $\endgroup$ – ogerard May 28 '15 at 7:09
  • $\begingroup$ Any hint or advice on how to properly handle the Heads->True / Level[0] options, even if I don't expect to need them myself ? $\endgroup$ – ogerard May 28 '15 at 7:11
  • $\begingroup$ @ogerard (1) Order of replacement is unimportant unless you are using evaluation at the time of rule application; rather order of evaluation within the entire expression after replacement is complete is critical. This is true for Map as well. (2) Heads and levelspec should be able to be handled however you like, but how is that? Give me a description and I'll (try to) give you an implementation. $\endgroup$ – Mr.Wizard May 28 '15 at 15:56

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.