12
$\begingroup$

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.

$\endgroup$
0

7 Answers 7

13
$\begingroup$

Yet another way would be this:

Thread[#1 -> #2] & @@@ lst
$\endgroup$
14
$\begingroup$
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}} *)
$\endgroup$
0
9
$\begingroup$

Another alternative is:

Thread /@ (Rule @@@ lst)
$\endgroup$
8
$\begingroup$

Since V 13.1 there is MapApply

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

Correct version (thanks to @kglr):

MapApply[Thread @* Rule] @ lst

{{1 -> a, 2 -> b}, {3 -> c, 4 -> d}}

$\endgroup$
2
  • $\begingroup$ you probably meant MapApply[Thread@*Rule]@lst? $\endgroup$
    – kglr
    Sep 20, 2023 at 12:10
  • $\begingroup$ Yes, corrected, thank you very much $\endgroup$
    – eldo
    Sep 20, 2023 at 13:00
6
$\begingroup$
 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 *)
$\endgroup$
3
$\begingroup$

Using Cases:

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

Cases[lst, {x : {__}, y : {__}} :> Rule @@@ {x, y}]

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

Also, combining Cases with MapThread:

Cases[lst, x : {__} :> MapThread[Rule, Transpose@x]]

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

Or using ReplaceAll:

lst /. x : {__} /; VectorQ[x] :> Rule @@ x

(*{{1 -> 2, a -> b}, {3 -> 4, c -> d}}*)
$\endgroup$
2
$\begingroup$

All the normal looking answers have been given.

Given a list

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

we can use

ArrayReshape[
 Inner[Rule, Select[lst // Flatten, Head[#] == Integer &], 
  Transpose@Variables[lst // Flatten], List], {Length@lst, 
  Length@lst}]
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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