3

If I want to do the following:

getCH[pts_List] := Module[{t}, t = ConvexHull[pts]; Map[Part[pts, #] &, t]];

or

Map[Function[{x}, Part[#, x]], ConvexHull[#]]&

What are other ways to write this? And how do you normally do for speed and efficiency?

Edit

BTW, I am asking this in a generic way, not for this particular problem. I sometimes feel the lack of brain power to think in terms of functional programming in mma. Just want to expand my arsenal with various other ways to write function compositions and learn the analysis of their complexity/efficiency. So please add similar problems.

Qiang Li
  • 10,593
  • 21
  • 77
  • 148
  • Sorry I only just saw your edit. The distinction between `Module` for local variables and `With` for local constants is generic. – Verbeia Dec 30 '11 at 23:25

3 Answers3

4

I don't know what a ConvexHull is but I'll assume I understood the problem

    getCH[pts_]:=pts[[ConvexHull[pts]]]


    getCH[pts_]:=Extract[pts, Transpose@{ConvexHull[pts]}]

If you want pts to appear only once for some reason you could always use With, Module or Block. I think most important is to say that I don't see the point in doing that. With, effectively replaces each appearance of pts with the list of points. Seems like an overkill for this but feel free to write

     getCH[pts_]:=With[{p=pts},p[[ConvexHull[p]]]]

Module creates a new variable. It's usually slower than With for cases in which your variable doesn't need to be asigned a value. In other words, With is faster for defining constants. Block I think is also faster than Module (slightly) but its dynamic scoping (against Module's lexical scoping) makes it a little bit weirder. Lots of threads about these.

I don't think there's any built-in function that takes a list and a function or symbol, and extracts elements on that list indexed by the result of evaluating the function on that same list, if that's what you were looking for for your "generic" problem. Of course you can create one easily and then use it in the future. I think it's too much for such a simple issue but perhaps its the functional programming you were aiming for

    ExtractIndexed[l_List, fun_]:=l[[fun[l]]]

    getCH[pts_]:=ExtractIndexed[pts, ConvexHull]
Rojo
  • 266
  • 3
  • 15
  • You can also consider `List /@ ...` instead of `Transpose@{...}`. – Szabolcs Jan 01 '12 at 13:29
  • 1
    @Szabolcs List/@ is probably clearer and as efficient in this case, but I have the habit of choosing Transpose when it fits for these things... Seems to be faster. Map is more general than Transpose which requires a List, a square matrix, etc – Rojo Jan 01 '12 at 14:28
  • 1
    Yes, your are right, for packed arrays it is definitely much faster. For curiosity, `Partition[..., 1]` is an equally fast (arguable less readable) alternative. – Szabolcs Jan 01 '12 at 15:04
3

You can initialize variables in a Module like this

Module[{t = ConvexHull[pts]}, Map[Part[pts, #] &, t]]

But in this case, you aren't redefining t, so it is a local constant and you are better off using With.

With[{t = ConvexHull[pts]}, Map[Part[pts, #] &, t]]

Or just

Map[Part[pts, #] &, ConvexHull[pts] ]

Or

Part[pts, #] & /@ ConvexHull[pts]

This question is related: Using nested slots. It is not recommended to nest pure functions without naming variables.

You could “invert” your function like so, but I can't guarantee it works.

Function[x,Part[#,x]]& /@ ConvexHull[#] & @ pts
Community
  • 1
  • 1
Verbeia
  • 4,400
  • 2
  • 23
  • 44
  • If I want to have `pts` just appear once, and also get rid of `Function` in `Map[Function[{x}, Part[#, x]], ConvexHull[#]]&`, is there a way, such as using @, /@, ~, etc? – Qiang Li Dec 30 '11 at 23:33
  • And normally I really don't want to write pts twice. – Qiang Li Dec 30 '11 at 23:34
1

Perhaps try using Through:

Part @@ Through[ 
 List[ Identity, Graphics`Mesh`ConvexHull][{{0, 0}, {1, 0}, {.5, .5}, {1, 1}, {0, 1}}]
]

This one gives a warning (because Part evaluates), but then 'works':

Through[
 Part[Identity, Graphics`Mesh`ConvexHull][{{0, 0}, {1, 0}, {.5, .5}, {1, 1}, {0, 
 1}}]]

I think this is a way around the Part evaluating issue above:

Through[
 Unevaluated[
  Part[
   Identity, Graphics`Mesh`ConvexHull][
   {{0, 0}, {1, 0}, {.5, .5}, {1, 1}, {0, 1}}
]]]
Arnoud Buzing
  • 15,383
  • 3
  • 20
  • 50