views:

140

answers:

3

Lets say I have a function f[x_, y_], and two lists l1, l2. I'd like to evaluate f[x,y] for each pair x,y with x in l1 and y in l2, and I'd like to do it without having to make all pairs of the form {l1[[i]],l2[[j]]}.

Essentially, what I want is something like Map[Map[f[#1, #2]&, l1],l2] where #1 takes values from l1 and #2 takes values from l2, but this doesn't work.

(Motivation: I'm trying to implement some basic Haskell programs in Mathematica. In particular, I'd like to be able to code the Haskell program

isMatroid::[[Int]]->Bool
isMatroid b =and[or[sort(union(xs\\[x])[y]'elem'b|y<-ys]|xs<-b,ys<-b, xs<-x]

I think I can do the rest of it, if I can figure out the original question, but I'd like the code to be Haskell-like. Any suggestions for implementing Haskell-like code in Mathematica would be appreciated.)

+5  A: 

To evaluate a function f over all pairs from two lists l1 and l2, use Outer:

In[1]:=  Outer[f, {a,b}, {x,y,z}]
Out[1]:= {{f[a,x],f[a,y],f[a,z]}, {f[b,x],f[b,y],f[b,z]}}

Outer by default works at the lowest level of the provided lists; you can also specify a level with an additional argument:

In[2]:=  Outer[f, {{1, 2}, {3, 4}}, {{a, b}, {c, d}}, 1]
Out[2]:= {{f[{1,2},{a,b}], f[{1,2},{c,d}]}, {f[{3,4},{a,b}], f[{3,4},{c,d}]}}

Note that this produces a nested list; you can Flatten it if you like.

My original answer pointed to Thread and MapThread, which are two ways to apply a function to corresponding pairs from lists, e.g. MapThread[f,{a,b},{1,2}] == {f[a,1], f[b,2]}.

P.S. I think as you're learning these things, you'll find the documentation very helpful. There are a lot of general topic pages, for example, applying functions to lists and list manipulation. These are generally linked to in the "more about" section at the bottom of specific documentation. This makes it a lot easier to find things when you don't know what they'll be called.

Jefromi
Neither of these works, though: if l1 = {1,2,3}, l2 = {x,y,z}, I want to evaluate f[x,y] on the 9 possible pairs (1,x), (1, y), ...,(3,y), (3,z). Both Thread and MapThread suck in elements at the same position in the two lists.
Leah Wrenn Berman
Oh, my bad. I misunderstood what you meant by "runs over". You'll want `Outer` then; it'll take me a minute to edit the answer up.
Jefromi
That's fantastic. Thanks!
Leah Wrenn Berman
@Leah: You're welcome! I'm still hoping someone will chime in about Haskell and Mathematica - I've been meaning to learn Haskell at some point.
Jefromi
A: 

In[1]:= list1 = Range[1, 5];

In[2]:= list2 = Range[6, 10];

In[3]:= (f @@ #) & /@ Transpose[{list1, list2}]

Out[3]= {f[1, 6], f[2, 7], f[3, 8], f[4, 9], f[5, 10]}

ragfield
@ragfield: This was my first thought as well, but Leah explicitly said "*without* having to make all pairs..." - so Transpose is out.
Jefromi
+3  A: 

To pick up on OP's request for suggestions about implementing Haskell-like code in Mathematica. A couple of things you'll have to deal with are:

  • Haskell evaluates lazily, by default Mathematica does not, it's very eager. You'll need to wrestle with Hold[] and its relatives to write lazily evaluating functions, but it can be done. You can also subvert Mathematica's evaluation process and tinker with Prolog and Epilog and such like.
  • Haskell's type system and type checking are probably more rigorous than Mathematica's defaults, but Mathematica does have the features to implement strict type checking.

I'm sure there's a lot more but I'm not terribly familiar with Haskell.

High Performance Mark