8
$\begingroup$

First I would like to find out how to negate a pattern and based on this I would like to solve this little problem on how to transform a list of strings to a JSON array. This is how I started working on the problem.

listEmptyQ[lst_List]:=Length[lst]==0

listToX[lst_List?listEmptyQ]:="[]"

listToX[lst_List /; Not[listEmptyQ[lst]]]:="["<>ToString[lst]<>"]"

listToX[{a, b}]
(* [{a, b}] *)

listToX[{}]
(* [] *)

So, I would like to avoid the constraint operator (/;) on the non-empty list case and turn this to a pattern test instead.

And is there a built-in predicate for testing an empty list ?

$\endgroup$
9
  • 1
    $\begingroup$ If you define listToX[{}] := "[]" first before the general case, then you don't need to worry about negations. $\endgroup$
    – J. M.'s torpor
    Jul 21 '15 at 8:20
  • $\begingroup$ Any reason not to write such a thing as listToX2[lst_List] := "[" <> StringReplace[ToString@lst, "{}" -> ""] <> "]"? $\endgroup$
    – ciao
    Jul 21 '15 at 8:28
  • 1
    $\begingroup$ To answer your first question, in version 10, listToX[lst_List?(Not@*listEmptyQ)] := .... In earlier versions listToX[lst_List?(Composition[Not, listEmptyQ])] := .... Or listToX[lst_List?(Not@listEmptyQ@# &)] := ... $\endgroup$ Jul 21 '15 at 9:19
  • 3
    $\begingroup$ Or listToX[lst : Except[_List?listEmptyQ]] := ... $\endgroup$ Jul 21 '15 at 9:21
  • $\begingroup$ @Guesswhoitis. You are right, but I wanted also to know the answer to my question for a general purpose. $\endgroup$ Jul 21 '15 at 9:57
3
$\begingroup$

I am answering the question in an interesting, thorough way for the reader based on the useful comments I had from other community members. I believe this example is excellent for demonstrating many pattern oriented features inside function definitions. Let me know what you think.

Predicate Definition

listEmptyQ[lst_List] := Length[lst] == 0

Testing List

testList = {{}, {"first", "second", "third"}};

The following function, defined in FIVE different ways, converts a list of strings to a json array. In this case, please also note that I have made the pattern more specific using BlankNullSequence of Strings

1.Without using the predicate listEmptyQ

The base case is defined first, so we do not need to define the predicate

listToX[{}] := "[]"
listToX[lst:{__String}] :="[" <> StringDrop[StringJoin@(("\"" <> # <> "\",") & /@ lst), -1] <> "]"

listToX /@ testList
(* {[],["first","second","third"]} *)

2.Pattern Test by Negating Predicate listEmptyQ

listToZ[lst:{__String}?listEmptyQ] := "[]"

listToZ[lst:{__String}?(Not@*listEmptyQ)] := "[" <> SringDrop[StringJoin@(("\"" <> # <> "\",") & /@ lst), -1] <> "]"

listToZ /@ testList
(* {[],["first","second","third"]} *)

3.Negate Constraint

listToY[lst:{__String} /; listEmptyQ[lst]] := "[]"
listToY[lst:{__String} /; Not[listEmptyQ[lst]]] :=  "[" <> StringDrop[StringJoin@(("\"" <> # <> "\",") & /@ lst), -1] <> "]"

listToY /@ testList
(* {[],["first","second","third"]} *)

4.Pattern Test Using Except

listToW[lst:{__String}?listEmptyQ] := "[]"
listToW[lst:Except[{__String}?listEmptyQ]] := "[" <> StringDrop[StringJoin@(("\"" <> # <> "\",") & /@ lst), -1] <> "]"

listToW /@ testList
(* {[],["first","second","third"]} *)

5.Using If

listToS[lst:{___String}]:= If[Length[lst] == 0, "[]","[" <> StringDrop[StringJoin@(("\"" <> # <> "\",") & /@ lst), -1] <> "]"]

listToS /@ testList
(* {[],["first","second","third"]} *)
$\endgroup$
6
  • $\begingroup$ Alternatively: listEmptyQ[l_] := l === {}. $\endgroup$
    – J. M.'s torpor
    Jul 21 '15 at 12:52
  • 1
    $\begingroup$ Or perhaps, listEmptyQ[{ }] = True; listEmptyQ[{__}] = False; $\endgroup$
    – m_goldberg
    Jul 21 '15 at 14:20
  • $\begingroup$ What I think about this is that it is much ado about very little. $\endgroup$
    – m_goldberg
    Jul 21 '15 at 14:27
  • 1
    $\begingroup$ +1 Unrelated to "negating a pattern test", but incidentally it is unnecessary to check listEmptyQ for the pattern {__String} (two underscores) since it will only match non-empty lists. The pattern {___String} (three underscores) will match both empty and non-empty lists. $\endgroup$
    – WReach
    Jul 21 '15 at 16:13
  • $\begingroup$ @WReach, you are right. I feel great to share my learning experience with the experts (that is to answer @m_goldberg). Working on this example I find that it makes a huge difference narrowing the pattern. In this specific transformation from a list of strings to a JSON array it becomes clear that the use of the listEmptyQ predicate is unnecessary, (see 5.). What is necessary is to define the base case on the recursive kind of StringJoin pure Function. Therefore I believe that the most elegant solutions are 1. and 5. $\endgroup$ Jul 21 '15 at 17:18

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.