Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

'Good' or 'Proper' Mathematica coding habits question

14 views
Skip to first unread message

Matt

unread,
Nov 9, 2005, 4:07:20 AM11/9/05
to
Hello,
Due to the great help I've received from here, I've made limited
progress with Mathematica. As I continue my journey, I am trying to adopt the
philosophy: "When working with Mathematica, shy away from your long-learned
habits of using loops, and instead try a functional or rule-based
approach." To this end, I have coded up a few functions, which I'd
appreciate any feedback on, as to whether I'm breaking an inviolate
rule of Mathematica, or I'm using an egregious memory model, I'm duplicating
some functionality that already exists in Mathematica proper, etc. Please bear
in mind that I am by training and thought process an assembly and C/C++
developer that worries about details such as whether to use
post-increment or post-increment when dealing with objects due to the
unnecessary construction of temporary objects on the stack. I want to
learn good Mathematica habits from the get-go.

Here are the functions with short explanations for each:

Cell[TextData[{
"extractNthElementFromEachSublistOfList takes as its first argument \
a list of lists, e.g. of the form {{",
Cell[BoxData[
FormBox[
SubscriptBox["l", "x"], TraditionalForm]]],
", ",
Cell[BoxData[
FormBox[
SubscriptBox["l", "y"], TraditionalForm]]],
"}, {",
Cell[BoxData[
FormBox[
SubscriptBox["l", "x"], TraditionalForm]]],
", ",
Cell[BoxData[
FormBox[
SubscriptBox["l", "y"], TraditionalForm]]],
"}, {",
Cell[BoxData[
FormBox[
SubscriptBox["l", "x"], TraditionalForm]]],
", ",
Cell[BoxData[
FormBox[
SubscriptBox["l", "y"], TraditionalForm]]],
"}, {",
Cell[BoxData[
FormBox[
SubscriptBox["l", "x"], TraditionalForm]]],
", ",
Cell[BoxData[
FormBox[
SubscriptBox["l", "y"], TraditionalForm]]],
"}} where each x and y subscript could denote any positive integer \
values to select from the set defined by 'l', and where 'l' could be \
an atomic object, or it could be itself an object with a head of List \
and an integer that specifies which element from each sublist to add \
to a list. This function will extract the nth element from each \
sublist of the input list and place it into a list and then return \
the flattened version of that list"
}], "Text"]

Cell[BoxData[{
RowBox[{
RowBox[{"Clear", "[",
RowBox[{
"extractNthElementFromEachSublistOfList", ",", "testRun"}],
"]"}], ";"}], "\[IndentingNewLine]",
RowBox[{
RowBox[{
RowBox[{"extractNthElementFromEachSublistOfList", "[",
RowBox[{"x_List", ",", "index_Integer", ",",
RowBox[{"debugOn", ":",
RowBox[{
RowBox[{"(",
RowBox[{"_", "?",
RowBox[{"(",
RowBox[{
RowBox[{
"#", " ", "\[Element]", " ", "Booleans"}],
" ", "&"}], ")"}]}], ")"}], ":",
"False"}]}]}], "]"}], " ", ":=", " ",
RowBox[{"Module", "[", "\[IndentingNewLine]",
RowBox[{
RowBox[{"{",
RowBox[{
RowBox[{"tempList", " ", "=", " ",
RowBox[{"{", "}"}]}], ",", "error", ",",
RowBox[{"noError", "=", "True"}], ",", "ret"}], "}"}],
",", "\[IndentingNewLine]",
RowBox[{
RowBox[{"If", "[",
RowBox[{
RowBox[{"debugOn", " ", "\[Equal]", " ", "True"}],
",", "\[IndentingNewLine]",
RowBox[{"error", "=",
RowBox[{"Catch", "[",
RowBox[{
RowBox[{
RowBox[{"(",
RowBox[{
RowBox[{"If", "[",
RowBox[{
RowBox[{"(",
RowBox[{
RowBox[{"bool", " ", "=", " ",
RowBox[{
RowBox[{
"Length", "[", "#", "]"}],
" ", "<", " ",
RowBox[{
"Abs", "[", "index",
"]"}]}]}], ";",
RowBox[{"Print", "[",
RowBox[{
"\"\<bool = \>\"", ",",
"bool"}], "]"}], ";",
"bool"}], ")"}], ",",
RowBox[{
RowBox[{"noError", "=", "False"}],
";",
RowBox[{
"Throw", "[", "#", "]"}]}]}],
"]"}], ";",
RowBox[{"tempList", " ", "=", " ",
RowBox[{"{",
RowBox[{"tempList", ",",
RowBox[{"#", "[",
RowBox[{"[", "index", "]"}],
"]"}]}], "}"}]}]}], ")"}], " ",
"&"}], " ", "/@", " ", "x"}], "]"}]}], ",",
"\[IndentingNewLine]",
RowBox[{"error", "=", "\[IndentingNewLine]",
RowBox[{"Catch", "[",
RowBox[{
RowBox[{
RowBox[{"(",
RowBox[{
RowBox[{"If", "[",
RowBox[{
RowBox[{
RowBox[{"Length", "[", "#", "]"}],
" ", "<", " ",
RowBox[{
"Abs", "[", "index", "]"}]}], ",",

RowBox[{
RowBox[{"noError", "=", "False"}],
";",
RowBox[{
"Throw", "[", "#", "]"}]}]}],
"]"}], ";",
RowBox[{"tempList", " ", "=", " ",
RowBox[{"{",
RowBox[{"tempList", ",",
RowBox[{"#", "[",
RowBox[{"[", "index", "]"}],
"]"}]}], "}"}]}]}], ")"}], " ",
"&"}], " ", "/@", " ", "x"}], "]"}]}]}],
"\[IndentingNewLine]", "]"}], ";",
"\[IndentingNewLine]",
RowBox[{"If", "[",
RowBox[{
RowBox[{"noError", "\[Equal]", "False"}], ",",
"\[IndentingNewLine]",
RowBox[{"ret", " ", "=", " ",
RowBox[{"\"\<An index of \>\"", "<>", " ",
RowBox[{"ToString", "[", "index", "]"}], "<>",
"\"\< is out of bounds for sublist \>\"", "<>",

RowBox[{"ToString", "[", "error", "]"}]}]}],
",", "\[IndentingNewLine]",
RowBox[{"ret", " ", "=",
RowBox[{"Flatten", "[", "tempList", "]"}]}]}],
"]"}], ";", "\[IndentingNewLine]", "ret"}]}],
"\[IndentingNewLine]", "]"}]}],
";"}], "\[IndentingNewLine]",
RowBox[{
RowBox[{
RowBox[{"testRun", "[",
RowBox[{"debugOn", ":",
RowBox[{
RowBox[{"(",
RowBox[{"_", "?",
RowBox[{"(",
RowBox[{
RowBox[{
"#", " ", "\[Element]", " ", "Booleans"}], " ",
"&"}], ")"}]}], ")"}], ":", "False"}]}], "]"}],
":=",
RowBox[{"Module", "[",
RowBox[{
RowBox[{"{",
RowBox[{
RowBox[{"testList", " ", "=", " ",
RowBox[{"{",
RowBox[{
RowBox[{"{",
RowBox[{"1", ",", "2"}], "}"}], ",", " ",
RowBox[{"{",
RowBox[{"1", ",", "3"}], "}"}], ",", " ",
RowBox[{"{",
RowBox[{"1", ",", "4"}], "}"}], ",", " ",
RowBox[{"{",
RowBox[{"1", ",", "5"}], "}"}], ",", " ",
RowBox[{"{",
RowBox[{"1", ",", "6"}], "}"}]}], "}"}]}],
",",
RowBox[{"unaryList", "=",
RowBox[{"{",
RowBox[{
"1", ",", "2", ",", "3", ",", "4", ",", "5", ",",
"6"}], "}"}]}]}], "}"}], ",",
"\[IndentingNewLine]",
RowBox[{
RowBox[{"Print", "[",
RowBox[{
"extractNthElementFromEachSublistOfList", "[",
RowBox[{"testList", ",", "1", ",", "debugOn"}],
"]"}], "]"}], ";", "\[IndentingNewLine]",
RowBox[{"Print", "[",
RowBox[{
"extractNthElementFromEachSublistOfList", "[",
RowBox[{"testList", ",",
RowBox[{"-", "2"}], ",", "debugOn"}], "]"}],
"]"}], ";",
RowBox[{"(*",
RowBox[{
"this", " ", "is", " ", "equivalent", " ", "to", " ",
"using", " ", "an", " ", "index", " ",
RowBox[{"of", " ", "'"}],
RowBox[{"1", "'"}]}], "*)"}], "\[IndentingNewLine]",

RowBox[{"Print", "[",
RowBox[{
"extractNthElementFromEachSublistOfList", "[",
RowBox[{"testList", ",", "2", ",", "debugOn"}],
"]"}], "]"}], ";"}]}], "\[IndentingNewLine]",
"]"}]}], ";"}], "\[IndentingNewLine]",
RowBox[{"testRun", "[", "]"}]}], "Input"]

Cell["\<\
findLeastOrGreatest is used to find within a given list of lists the \
least or greatest value in a column dictated by pos. Whether the \
least or greatest is determined is controlled by an optional \
parameter, 'greaterThan', which if given explicitly as 'False' will \
find the least value.\
\>", "Text"]

Cell[BoxData[{
RowBox[{
RowBox[{"Clear", "[",
RowBox[{"findLeastOrGreatest", ",", "testRun"}], "]"}],
";"}], "\[IndentingNewLine]",
RowBox[{
RowBox[{
RowBox[{"findLeastOrGreatest", "[",
RowBox[{
RowBox[{"inList_List", "?",
RowBox[{"(",
RowBox[{
RowBox[{"(",
RowBox[{
RowBox[{"Depth", "[", "#", "]"}], "\[Equal]",
"3"}], ")"}], " ", "&"}], ")"}]}], ",", " ",
RowBox[{"pos", ":",
RowBox[{"(",
RowBox[{"_Integer", "?",
RowBox[{"(",
RowBox[{
RowBox[{
RowBox[{"Positive", "[", "#", "]"}], " ", "&&",
" ",
RowBox[{"#", " ", "<", " ", "3"}]}], "&"}],
")"}]}], ")"}]}], ",",
RowBox[{"greaterThan", ":",
RowBox[{
RowBox[{"(",
RowBox[{"_", "?",
RowBox[{"(",
RowBox[{
RowBox[{
"#", " ", "\[Element]", " ", "Booleans"}],
" ", "&"}], ")"}]}], ")"}], ":", "True"}]}]}],
"]"}], " ", ":=", " ",
RowBox[{"Module", "[",
RowBox[{
RowBox[{"{",
RowBox[{"op", "=", "GreaterEqual"}], "}"}], ",",
"\[IndentingNewLine]",
RowBox[{
RowBox[{"If", "[",
RowBox[{
RowBox[{
"False", " ", "\[Equal]", " ", "greaterThan"}], ",",

RowBox[{"op", "=", "Less"}]}], "]"}], ";",
"\[IndentingNewLine]",
RowBox[{"IntegerPart", "[",
RowBox[{
RowBox[{"Fold", "[",
RowBox[{
RowBox[{
RowBox[{"If", "[",
RowBox[{
RowBox[{"op", "[",
RowBox[{
RowBox[{"#1", "[",
RowBox[{"[", "pos", "]"}], "]"}],
",", " ",
RowBox[{"#2", "[",
RowBox[{"[", "pos", "]"}], "]"}]}],
"]"}], ",", "#1", ",", "#2"}], "]"}],
" ", "&"}], ",",
RowBox[{"inList", "[",
RowBox[{"[", "1", "]"}], "]"}], ",",
"inList"}], "]"}], "[",
RowBox[{"[", "pos", "]"}], "]"}], "]"}]}]}],
"\[IndentingNewLine]", "]"}]}],
";"}], "\[IndentingNewLine]",
RowBox[{
RowBox[{
RowBox[{"testRun", "[", "]"}], ":=",
RowBox[{"Module", "[",
RowBox[{
RowBox[{"{",
RowBox[{"testList", " ", "=", " ",
RowBox[{"{",
RowBox[{
RowBox[{"{",
RowBox[{"1", ",", "2"}], "}"}], ",", " ",
RowBox[{"{",
RowBox[{"1", ",", "3"}], "}"}], ",", " ",
RowBox[{"{",
RowBox[{"1", ",", "4"}], "}"}], ",", " ",
RowBox[{"{",
RowBox[{"1", ",", "5"}], "}"}], ",", " ",
RowBox[{"{",
RowBox[{"1", ",", "6"}], "}"}]}], "}"}]}],
"}"}], ",", "\[IndentingNewLine]",
RowBox[{
RowBox[{"Print", "[",
RowBox[{"findLeastOrGreatest", "[",
RowBox[{"testList", ",", "1"}], "]"}], "]"}], ";",
"\[IndentingNewLine]",
RowBox[{"Print", "[",
RowBox[{"findLeastOrGreatest", "[",
RowBox[{"testList", ",", "2", ",", "False"}], "]"}],
"]"}], ";", "\[IndentingNewLine]",
RowBox[{"Print", "[",
RowBox[{"findLeastOrGreatest", "[",
RowBox[{"testList", ",", "2"}], "]"}], "]"}],
";"}]}], "\[IndentingNewLine]", "]"}]}],
";"}], "\[IndentingNewLine]",
RowBox[{"testRun", "[", "]"}]}], "Input"]

Here is a table of 20 pairs of numbers.
values = Table[{Random[Real, {-2, 2}] i, Random[Real, {-2,2}] i}, {i,
1, 20}];

I want to extract all elements from 'values' where each of the values
of a particular element are negative. This was my first approach:
negElems = {};
(If[Negative[#[[1]]] && Negative[#[[2]]], negElems = {negElems, #}]) &
/@ values
negElems
Flatten[%]
Partition[%, 2]

I didn't like that approach particularly because it created a
'temporary' list with many Nulls embedded in it. So, then I tried a
Fold approach:

negElems = {};
Fold[If[Negative[#2[[1]]] && Negative[#2[[2]]], negElems = {negElems,
#2}, negElems] &, values[[1]], values];
Flatten[%]
Partition[%, 2]

That seems 'nicer', but I'm sure there's even better and more efficient
ways of doing this (or perhaps, what I've done is as bad as bad can
be).

All feedback is appreciated.

Thanks,

Matt

Carl K. Woll

unread,
Nov 10, 2005, 3:10:00 AM11/10/05
to
Matt wrote:
> Hello,
> Due to the great help I've received from here, I've made limited
> progress with Mathematica. As I continue my journey, I am trying to adopt the
> philosophy: "When working with Mathematica, shy away from your long-learned
> habits of using loops, and instead try a functional or rule-based
> approach." To this end, I have coded up a few functions, which I'd
> appreciate any feedback on, as to whether I'm breaking an inviolate
> rule of Mathematica, or I'm using an egregious memory model, I'm duplicating
> some functionality that already exists in Mathematica proper, etc. Please bear
> in mind that I am by training and thought process an assembly and C/C++
> developer that worries about details such as whether to use
> post-increment or post-increment when dealing with objects due to the
> unnecessary construction of temporary objects on the stack. I want to
> learn good Mathematica habits from the get-go.
>
> Here are the functions with short explanations for each:
>

[snip]

Matt first wants a function which extracts the nth element from each
sublist. The simplest way is to use Part with All:

testlist = {{1, 2}, {1, 3}, {1, 4}, {1, 5}, {1, 6}}

testlist[[All,1]]
testlist[[All,-1]]

etc.

Matt then wants a function which finds the maximum or minimum of a
column. Use Max or Min:

Max[testlist[[All,2]]]

etc.

>
> Here is a table of 20 pairs of numbers.
> values = Table[{Random[Real, {-2, 2}] i, Random[Real, {-2,2}] i}, {i,
> 1, 20}];
>
> I want to extract all elements from 'values' where each of the values
> of a particular element are negative. This was my first approach:
> negElems = {};
> (If[Negative[#[[1]]] && Negative[#[[2]]], negElems = {negElems, #}]) &
> /@ values
> negElems
> Flatten[%]
> Partition[%, 2]
>
> I didn't like that approach particularly because it created a
> 'temporary' list with many Nulls embedded in it. So, then I tried a
> Fold approach:
>
> negElems = {};
> Fold[If[Negative[#2[[1]]] && Negative[#2[[2]]], negElems = {negElems,
> #2}, negElems] &, values[[1]], values];
> Flatten[%]
> Partition[%, 2]
>

For this problem, Cases seems like the simplest approach:

Cases[ values, {_?Negative,_?Negative} ]

> That seems 'nicer', but I'm sure there's even better and more efficient
> ways of doing this (or perhaps, what I've done is as bad as bad can
> be).
>

Remember that Mathematica has many builtin functions, and of course, in
general it is best to make use of the appropriate function whenever you
can. Part of the process of learning Mathematica is becoming familiar
with various subsets of these builtin functions.

> All feedback is appreciated.
>
> Thanks,
>
> Matt

Carl Woll
Wolfram Research

Igor Antonio

unread,
Nov 10, 2005, 3:22:13 AM11/10/05
to
Matt wrote:
> Hello,
> Due to the great help I've received from here, I've made limited
> progress with Mathematica. As I continue my journey, I am trying to adopt the
> philosophy: "When working with Mathematica, shy away from your long-learned
> habits of using loops, and instead try a functional or rule-based
> approach." To this end, I have coded up a few functions, which I'd
> appreciate any feedback on, as to whether I'm breaking an inviolate
> rule of Mathematica, or I'm using an egregious memory model, I'm duplicating
> some functionality that already exists in Mathematica proper, etc. Please bear
> in mind that I am by training and thought process an assembly and C/C++
> developer that worries about details such as whether to use
> post-increment or post-increment when dealing with objects due to the
> unnecessary construction of temporary objects on the stack. I want to
> learn good Mathematica habits from the get-go.
>

That's a good idea to change your way of thinking when dealing with a functional
language from the start. :-)

Here's advice about the newsgroup though, please post the InputForm of your code
on the newsgroup. This way we can read the code without having to copy and
paste it into Mathematica.

> Here are the functions with short explanations for each:
>

> Cell[TextData[{
> "extractNthElementFromEachSublistOfList takes as its first argument \
> a list of lists, e.g. of the form {{",

<celldata stuff>

I copied and pasted into Mathematica and got a cell expression error. I might
have copied and pasted something wrong, but please post the InputForm of it.


> Here is a table of 20 pairs of numbers.
> values = Table[{Random[Real, {-2, 2}] i, Random[Real, {-2,2}] i}, {i,
> 1, 20}];
>

Mathematica's Help Browser is a little hard to navigate when you first start,
but once you learn how it's organized, you will figure out a way to find what
you want.

When you want to extract data from a list based on certain conditions, your best
bet is to use the functions Select or Cases. (Help Browser > List and Matrices
> Element Extraction >). If you can use either one, choose Cases since it
works with pattern matching as opposed to element testing.

In[2]:= values = Table[{Random[Real, {-2, 2}]*i, Random[Real, {-2, 2}]*i}, {i,
1, 20}];

In[3]:= Cases[values, {a_?Negative, b_?Negative}]

Out[3]= {{-0.15028289650316573, -1.9370549678832405}, {-13.809144185126259,
-5.175134014000584}, {-26.68175865090242, -18.61024953825357}}

> All feedback is appreciated.
>
> Thanks,
>
> Matt


--


Igor C. Antonio
Wolfram Research, Inc.
http://www.wolfram.com

To email me personally, remove the dash.

Chris Chiasson

unread,
Nov 10, 2005, 3:29:07 AM11/10/05
to
Matt,
I couldn't paste your cell expression into my notebook without errors.
>From reading your message, may I suggest the use of Cases, especially
the form with the transformation rule?
Regards,

Matt

unread,
Nov 11, 2005, 3:13:49 AM11/11/05
to
Thank you all for your help. My apologies for the broken cells. How
do I get InputForm? I assume I need to do something like:
Cell->Display As->InputForm, then select the text in the cell and copy
it as 'Plain Text'. Is that right? If not, how do I make sure to get
the proper form associated with InputForm into the newsgroup?

Thanks,
Matt

Jean-Marc Gulliet

unread,
Nov 12, 2005, 3:40:58 AM11/12/05
to
Hi Matt,

First, select the cell(s) you want to convert in *InputForm* by clicking
on the right bracket of each cell or group of cells (you can also use
the "shift" and "control" keys). Then type in the group of keys
"shift"+"control"+"i" and then "control"+"c" to copy the cells.

A detail list of shortcuts for Windows, Macintosh and Linux can be found
in Help Browser -> Front End -> Keyboard Shortcuts

Best regards,
/J.M.

David Park

unread,
Nov 12, 2005, 3:47:48 AM11/12/05
to
Matt,

Copy the cell, if you want to preserve the original cell, select it and use
Shift-Ctrl-I to convert it to InputForm. Then copy that and paste it into
your posting.
You can convert a cell back to StandardForm by using Shift-Ctrl-N.
Converting between forms loses comments.

David Park
dj...@earthlink.net
http://home.earthlink.net/~djmp/

Chris Chiasson

unread,
Nov 12, 2005, 3:55:52 AM11/12/05
to
Just highlight whatever cells you want to copy, right click, and choose
copy as > cell expression. This is probably what you did already. The
only problem is making sure not to delete any parts of the cell
expression, such as the list that wraps the entire selection or the
CellGroup head, etc.

0 new messages