14

I would like to create a mapping from a list and I am wondering if there is a slick way of doing it.

For example, consider the list

ls = WaveletFilterCoefficients[DaubechiesWavelet[2], "PrimalHighpass"]

{{-2, -0.0915064},{-1, -0.158494},{0, 0.591506},{1, -0.341506}}

I would like to define a function that maps

 -2 -> -0.0915064
 -1 -> -0.158494
  0 ->  0.591506
  1 -> -0.341506

and all other integers to zero.

Any suggestions?

Mr.Wizard
  • 271,378
  • 34
  • 587
  • 1,371
Ryogi
  • 1,076
  • 6
  • 16

5 Answers5

16

Scan[] is your friend:

Scan[(f[First[#]] = Last[#]) &, 
  WaveletFilterCoefficients[DaubechiesWavelet[2], "PrimalHighpass"]];
f[_] = 0;

??f
  Global`f
f[-2]=-0.0915064

f[-1]=-0.158494

f[0]=0.591506

f[1]=-0.341506

f[_]=0
J. M.'s missing motivation
  • 124,525
  • 11
  • 401
  • 574
9

You could easily create a pattern doing the replacement for you:

ls = WaveletFilterCoefficients[DaubechiesWavelet[2], "PrimalHighpass"];
rule = Rule @@@ ls
{-2 -> -0.0915064,
 -1 -> -0.158494,
  0 ->  0.591506,
  1 -> -0.341506}

This can now be used as usual, for example

{-1, 1} /. rule
{-0.158494, -0.341506}

If you want to map all integers to 0, append (!) this to your rule list:

AppendTo[rule, _ -> 0];
{-2 -> -0.0915064,
 -1 -> -0.158494,
  0 ->  0.591506,
  1 -> -0.341506,
  _ -> 0}

Be careful though, because when you apply this to a list as before it'll match the whole list as _, replacing it with 0:

1 /. rule
-0.341506
{0, 1} /. rule
0

To properly do the list replacement in this case, use something like

myReplace = # /. rule &;
myReplace /@ {0, 1}
{0.591506, -0.341506}
David
  • 14,911
  • 6
  • 51
  • 81
9

Depending on your application this may be most efficient:

pts =
  {{-2, -0.0915064},
   {-1, -0.158494},
   { 0,  0.591506},
   { 1, -0.341506}};

f = Interpolation[pts, InterpolationOrder -> 0];

f /@ {1, -1, -2, 0}
{-0.341506, -0.158494, -0.158494, 0.591506}

This assumes that your function will only be given arguments that are in your list rather that points between them, which will otherwise effectively give f[Floor[#]] &.


Also, I recognize the advantage of Scan but I cannot pass the syntactical elegance of:

(f[#] = #2) & @@@ pts; 
Mr.Wizard
  • 271,378
  • 34
  • 587
  • 1,371
7

Why not use Replace?

ls = WaveletFilterCoefficients[DaubechiesWavelet[2], "PrimalHighpass"];    

Attributes[func] = {Listable};
func[x_] := Replace[x, Apply[Rule, ls, {1}]];

func[{1, 0, -1, -2}]

(*
   ==> {-0.341506, 0.591506, -0.158494, -0.0915064}
*)
István Zachar
  • 47,032
  • 20
  • 143
  • 291
5

Another way is to use Map i.e. /@ :

 l= WaveletFilterCoefficients[DaubechiesWavelet[2], "PrimalHighpass"];    
 Set[f[#[[1]]], #[[2]]] & /@ l;  
 f[_] = 0;
 f /@ Range[-3, 3]
 (*
 ==>  {0, -0.0915064, -0.158494, 0.591506, -0.341506, 0, 0}
 *) 
Artes
  • 57,212
  • 12
  • 157
  • 245
  • 1
    The problem with this is that Map[] can have the side-effect of producing output, which might be problematic if the list is long, and you've forgotten the semicolon. Scan[] is guaranteed not to produce output. – J. M.'s missing motivation Feb 16 '12 at 00:51
  • 1
    @J.M. Sorry, where have I missed the semicolon ? – Artes Feb 16 '12 at 00:57
  • You didn't, but it's a common mistake to forget semicolons for delineating different expressions. – J. M.'s missing motivation Feb 16 '12 at 01:06
  • 1
    @J.M. I'd add that even if you don't miss a semicolon, memory is allocated and list is internally created when Map is used. So, Map and Scan have very different memory use characteristics. If Scan can be used (meaning no output is needed), it is IMO better to use it than Map. Also, conceptually, this makes an intent of producing side-effects more clear / transparent. – Leonid Shifrin Feb 16 '12 at 07:52
  • Ah, of course. Thanks for filling in, @Leonid! – J. M.'s missing motivation Feb 16 '12 at 08:45
  • 1
    @J.M. But I must admit that I also sometimes use Map in such situations (just because its syntax is more concise :)) – Leonid Shifrin Feb 16 '12 at 13:19