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.

Just a light weight question for learning. If you think this was asked before, please feel free to close it.

I am trying to learn MapThread more, and wanted to use it to generate Rule from a list like this

lst = {{1, 2},{a, b}}

in order to obtain

(* {1 -> a, 2 -> b}  *)

Using MapThread works nice:

MapThread[Rule, lst]
(* {1 -> a, 2 -> b}  *)

But when the list contain more than one list in it, like this

lst = {{{1, 2}, {a, b}}, {{3, 4}, {c, d}}}

Then I could not find a way to use MapThread on its own on the whole list. It needs help to iterate over all the lists. So what I do now is Map the function MapThread on each list in the list. Like this

Map[ MapThread[Rule, #] &,  lst]
(*  {{1 -> a, 2 -> b}, {3 -> c, 4 -> d}}  *)

I did not want to do this:

MapThread[Rule, ArrayFlatten[{lst}]]
(* {1 -> a, 2 -> b, 3 -> c, 4 -> d} *)

because it loses the structure I had at the start, even though I can correct things with

Partition[%, 2]
(* {{1 -> a, 2 -> b}, {3 -> c, 4 -> d}} *)

But it seems not a good way to do it.

Question is: What is the recommended way to do this type of operation? Can MapThread be told to do this on its own without the help of Map? Are there other commands to do the above that you think are better?

I used Rule above, but you can replace that with any function f that takes 2 arguments.

Update 12/26/12

Fyi, I made a small addition to the solution so that it can be also used for 2D matrix, in addition to the 3D matrix (since this was not part of what I was asking originally).

Here is my changes. I found that the trick is to tell Apply the level to use. For 2D matrix, use level 0 or {}. But for 3D matrix, use {1}. This assumes the input is either 2D or 3D.

So this is how it looks now:

f[lst_List] :=Apply[Thread[Rule[#1, #2]] &, lst,If[MatrixQ[lst], Sequence @@ {}, {1}]]
f[ {{1, 2}, {a, b}} ]
(* {1 -> a, 2 -> b} *)

and

f[ {{{1, 2}, {a, b}}, {{3, 4}, {c, d}}}]
(*  {{1 -> a, 2 -> b}, {3 -> c, 4 -> d}} *)

Another way I could have done this, is by making 2 function definitions

f[lst_?(MatrixQ[#] &)] := Apply[Thread[Rule[#1, #2]] &, lst]
f[lst_List] := Apply[Thread[Rule[#1, #2]] &, lst, {1}]

But I personally never liked this type of coding much. Because now the logic is spread around, instead of all being contained in one place that is easier to see and maintain, So I normally like to have one function, and inside it, add the different logic needs for different values and types of the input, rather than define many different functions.

share|improve this question

4 Answers 4

up vote 8 down vote accepted

Yet another way would be this:

Thread[#1 -> #2] & @@@ lst
share|improve this answer
 Inner[Rule, Sequence @@ #, List] & /@ lst
 Apply[Rule, Transpose /@ lst, {2}]
 Apply[Rule, Thread /@ lst, {2}]
 (* {{1 -> a, 2 -> b}, {3 -> c, 4 -> d}} *)

where

 lst = {{{1, 2}, {a, b}}, {{3, 4}, {c, d}}}

EDIT: For inputs with different depths:

  thrdRlF = Apply[Rule, Thread /@ #, {Depth[#] - 2}] &
  thrdRlF[lst]
  (* {{1 -> a, 2 -> b}, {3 -> c, 4 -> d}} *)
  thrdRlF[lst[[1]]]
  (* {1 -> a, 2 -> b} *)
  thrdRlF[lst[[1,1]]]
  (* 1 -> 2 *)
  thrdRlF[lst[[1,1,1]]]
  (* 1 *)
share|improve this answer

Another alternative is:

Thread /@ (Rule @@@ lst)
share|improve this answer
lst = {{{1, 2}, {a, b}}, {{3, 5}, {4, f}}}

You could also do

MapThread[Rule, lst\[Transpose] , 2]
(* {{1 -> a, 2 -> b}, {3 -> 4, 5 -> f}} *)
share|improve this answer

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.