Functional mapping on a list of points
I have a list of points:
points = {{0.144, 1.20}, {0.110, 1.60}, {0.083, 2.00}, {0.070, 2.40},
{0.060, 2.80}, {0.053, 3.20}, {0.050, 3.60}, {0.043, 4.00}}
I want to p开发者_如何学编程ass each point to this function, returning a new point:
coordinate[length_,frequence_] = {(1/(2*length)) , (frequence*1000)}
Which should result in a list like so:
{ {3.47, 12 000}, {4.54, 16 000}, ... }
I've been trying to do so with map:
data = Map[coordinate, points]
It yields something like:
{coordinate[{0.144, 1.2}], coordinate[{0.11, 1.6}]}
At first that seems correct, except it passes a list rather than just arguments. However, even if I change my coordinate
function to accept a list (by changing the expected parameter to list_
and changing length
to list[[1]]
and frequence
to list[[2]]
), I won't be able to use the list returned by that map for e.g. linear regression by LinearModelFit[data, x, x]["BestFit"]
.
The simplest way that uses your definition, is Apply
at level 1 which has the shorthand @@@
. (See the more info part of the Apply documentation.) So, you want
points = {{0.144, 1.20}, {0.110, 1.60}, {0.083, 2.00}, {0.070,
2.40}, {0.060, 2.80}, {0.053, 3.20}, {0.050, 3.60}, {0.043, 4.00}}
coordinate[length_, frequence_] := {(1/(2*length)), (frequence*1000)}
coordinate @@@ points
Note that I've changed your definition into a SetDelayed
instead of just Set
(pay attention to the syntax highlighting showing you the localized variables on the right hand side). See the Immediate and Delayed Definitions guide page.
This said, it's probably best to make coordinate
take a list instead of a sequence, as done in belisarius' and ninjagecko's answers, i.e.,
coordinate[{length_, frequence_}] := {(1/(2*length)), (frequence*1000)}
coordinate[{length_, frequence_}] := {(1/(2*length)), (frequence*1000)}
data = coordinate /@ points
(*
->{{3.47222, 1200.}, {4.54545, 1600.}, {...
*)
And
lm = LinearModelFit[data, x, x]
(*
-> -40.3573 + 348.678 x
*)
Show[ListPlot[data], Plot[lm[x], {x, 0, 15}], Frame -> True]
Change your definition to
coordinate[point_] := {(1/(2*point[[1]])) , (point[[2]]*1000)}
coordinate[{length_, frequence_}] := {1/(2*length), frequence*1000}
coordinate /@ points
sidenote: I would personally stay away from the @@@
that has been proposed in other answers, since it feels awkward to me as a programmer. But those answers are also certainly valid.
Alternatively, you could use Apply
instead of Map
:
coordinate @@@ points
output:
{{3.47222, 1200.}, {4.54545, 1600.}, {6.0241, 2000.}, {7.14286, 2400.},
{8.33333, 2800.}, {9.43396, 3200.}, {10., 3600.}, {11.6279, 4000.}}
I feel that @@@
is the cleanest way to handle this. However, if you can to redefine coordinate
but you do not want remove its existing syntax, you may consider this construct.
Clear[coordinate]
coordinate[length_, frequence_] := {(2 length)^-1, 1000 frequence}
coordinate[l_List] := Apply[coordinate, l, {-2}]
The new line adds a definition to handle lists. This assumes that your arguments are not themselves objects with depth. It allows for quite a bit of flexibility in the way you use the function:
coordinate[0.144, 1.20]
(*Out= {3.47222, 1200.} *)
coordinate[{0.144, 1.20}]
(*Out= {3.47222, 1200.} *)
coordinate[points]
(*Out= {{3.47222, 1200.}, {4.54545, 1600.}, {6.0241,
2000.}, {7.14286, 2400.}, {8.33333, 2800.}, {9.43396, 3200.}, {10.,
3600.}, {11.6279, 4000.}} *)
coordinate /@ points
(*Out= {{3.47222, 1200.}, {4.54545, 1600.}, {6.0241,
2000.}, {7.14286, 2400.}, {8.33333, 2800.}, {9.43396, 3200.}, {10.,
3600.}, {11.6279, 4000.}} *)
coordinate @@@ points
(*Out= {{3.47222, 1200.}, {4.54545, 1600.}, {6.0241,
2000.}, {7.14286, 2400.}, {8.33333, 2800.}, {9.43396, 3200.}, {10.,
3600.}, {11.6279, 4000.}} *)
精彩评论