Take the 2-minute tour ×
Mathematica Stack Exchange is a question and answer site for users of Mathematica. It's 100% free, no registration required.

Suppose that I want to write a function fun that takes an Integer num as input, and returns Red if num == 1, Orange if num == 2, and Yellow if num == 3. One way, I think, to do this is to use Which:

fun[num_Integer] := Which[num == 1, Red, num == 2, Orange, num == 3, Yellow]

Is there a more concise way to write fun? In other words, is there any built-in function (analogous to Which) that I can use that would allow me to avoid typing "num" all the time instead of always having to specify it to Which. Writing fun as a series of nested If statements would be even lengthier.

Do you have any suggestions? Thanks for your time.

share|improve this question
1  
I usually use Switch as per @jVincent below –  Mike Honeychurch Jan 14 '13 at 23:00
    
Every single one of the methods I thought of are already in the four answers below. That doesn't happen often. Nice coverage guys! –  Mr.Wizard Jan 15 '13 at 2:46

4 Answers 4

up vote 26 down vote accepted

Not really a concise syntax, but you can also do this using Switch, which removes the need for writting the checking, and also allows patterns:

fun[num_Integer] :=
  Switch[num,
  1, "Red",
  2, "Orange",
  3, "Yellow",
  _?PrimeQ, "Purple",
  _, "LightGray"]

I used strings just to make the output nicer to verify the behavior. Naturally you would switch these to the actual colors.

Style[#, fun@#] & /@ Range@20

Numbers colored using the function

share|improve this answer

One simple solution is:

fun[1] = Red;
fun[2] = Orange;
fun[3] = Yellow;

A more complex solution that accepts arbitrary equivalence lists at run time:

fun[{ins_, outs_}] :=  Function[x, Piecewise[MapThread[{#2, x == #1} &, {ins, outs}], x]];

f = fun[{{1, 2, 3}, {Red, Orange, Yellow}}];

f[2]

RGBColor[1, 0.5, 0]

share|improve this answer
4  
I think it is a little more efficient to use fun[1]=Red,etc. Using := means that the token Red will evaluated on every call to fun, rather than once. –  m_goldberg Jan 15 '13 at 0:15
    
@m_goldberg, I don't think it makes any difference. –  Rojo Jan 15 '13 at 1:49
    
If you do f[_]=x; x=2;, then f[9] will have to reevaluate x regardless of having used an immediate assignment. If MMA is smart enough to not check when the assignment is to an atom, them it probably is also smart enough with a delayed assignment. But I'm not certain –  Rojo Jan 15 '13 at 1:51
1  
Ok, Forget what I said, I forgot that Red and friends actually evaluate to RGBColor –  Rojo Jan 15 '13 at 1:56
2  
One sleeps, magic happens. –  image_doctor Jan 15 '13 at 8:28

For example you may do something like

f[i_] := {Red,Orange,Yellow}[[i]]

Edit

You can easily add some robustness:

f[l_List, i_Integer ] := l[[i]] /; 1 <= i <= Length@l;

ll = {Red, Orange, Blue};
f[ll, 3]
share|improve this answer

You could use ReplaceAll to write your function this way:

fun[num_Integer] := num /. {1 -> Red, 2 -> Orange, 3 -> Yellow}

This also allows pattern matching, and works better than switch in case you want to name parts of your pattern:

findpeople[dbconn_, name_] := DBSelect[dbconn, "People", name] /. {
   $Failed :> (Message[findpeople::conn]; $Failed),
   {} :> (Message[findpeople::empty]; $Failed),
       results_List :> results,
       other_ :> (Message[findpeople::err, other]; $Failed)
}
share|improve this answer
1  
Big +1. Not enough love for this answer, folks! The possibility to transparently incorporate error-handling is very valuable. I use similar constructs a lot too. –  Leonid Shifrin Jan 15 '13 at 10:03
2  
+1, you might want to use Replace instead of ReplaceAll for slightly more robustness when replacing unexpected expressions... –  Albert Retey Jan 15 '13 at 11:19

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.