8
$\begingroup$

I am fairly new to mathematica. I was given two lists i.e {x1, x2, x3, x4} and {a,b,c,d} and I had to produce the following:

{x1->a,x2->b,x3->c,x4->d}

What I did was the following:

listToRules =Thread[{x1, x2, x3, x4} -> {a, b, c,d}]

But then I noticed that I was asked to write a function that does this. And I was also asked to write a function RulesTolist[rule1] that extracts and returns the two lists from a substitution list. So is what required different then what I did?

$\endgroup$
3
  • 1
    $\begingroup$ This seems more like a question for whoever asked you to do this than StackExchange. For the reverse operation, check out Keys and Values. $\endgroup$
    – Chris K
    Jan 2 at 19:09
  • $\begingroup$ but is what I wrote as a solution qualified as "utilizing a function" to solve the problem? $\endgroup$
    – imbAF
    Jan 2 at 19:10
  • $\begingroup$ This post Interlacing a single number into a long list is closely related. Take a closer look at this answer. $\endgroup$
    – Artes
    Jan 3 at 3:48

8 Answers 8

7
$\begingroup$

But then I noticed that I was asked to write a function that does this

may be the HW meant not to use Thread? One way could be to write a function like this

L1 = {x1, x2, x3, x4}
L2 = {a, b, c, d}
listToRules[L1_List, L2_List] := Module[{},
  If[Length@L1 != Length@L2, Abort[]];
  (L1[[#]] -> L2[[#]]) & /@ Range[Length@L1]
  ]

Now call it using

listToRules[L1, L2]

Mathematica graphics

If pure functions are not allowed, you can use loop, like this

listToRules[L1_List, L2_List] := Module[{n},
  If[Length@L1 != Length@L2, Abort[]];
  Last@Reap@Do[
     Sow[L1[[n]] -> L2[[n]]], {n, Length@L1}
     ]
  ];
listToRules[L1, L2]

Mathematica graphics

There are many other ways to do this without using Thread

And I was also asked to write a function RulesTolist[rule1]

I assume you mean, given {x1 -> a, x2 -> b, x3 -> c, x4 -> d} you want a function that returns back {{x1, x2, x3, x4},{a, b, c, d}} ? One way could be

rulesTolist[L_List] := Module[{r},
  r = Cases[L, Rule[a_, b_] :> {a, b}];
  {r[[All, 1]], r[[All, 2]]}
  ]

To use it

L = {x1 -> a, x2 -> b, x3 -> c, x4 -> d}
rulesTolist[L]

Mathematica graphics

Mathematica is a very flexible language, and there are many ways to do these things, the above is just one of these ways.

$\endgroup$
4
  • $\begingroup$ thank you for this. I don't have the slightest clue about mathematica. It's seems, at least to me, unnecessarily over complicated compared to python,c++ etc $\endgroup$
    – imbAF
    Jan 2 at 19:50
  • $\begingroup$ one question: L1_List, L2_List are the arguments here? of type list? And: does this part : "& /@ Range[Length@L1]" forces a loop with as many steps as the length of the list, in order to "tie" elements of both lists? $\endgroup$
    – imbAF
    Jan 2 at 20:19
  • 2
    $\begingroup$ @imbAF Yes, L1 and L2 are the arguments. The L_List just gives a type to L. it says that L is a list. So Mathematica will check that for you. It is a good feature. If you do not want it, you can just use listToRules[L1_, L2_] $\endgroup$
    – Nasser
    Jan 2 at 20:23
  • 1
    $\begingroup$ @imbAF & /@ Range[Length@L1] Yes. This is basically maps a pure function on list generated by the function Range[Length@L1 it is basically a loop but done in functional way. Mathematica is really a functional programming language, while Python is OO based language. $\endgroup$
    – Nasser
    Jan 2 at 20:24
7
$\begingroup$
{x1 -> a, x2 -> b, x3 -> c, x4 -> d} // FullForm

List[Rule[x1, a], Rule[x2, b], Rule[x3, c], Rule[x4, d]]

so it's a "matrix"


rulesTolist = (# /. Rule -> List // Transpose)&;
{x1 -> a, x2 -> b, x3 -> c, x4 -> d} // rulesTolist

Or, use Association

rulesTolist = (# // Association // KeyValueMap[List] // Transpose)&;
{x1 -> a, x2 -> b, x3 -> c, x4 -> d} // rulesTolist
$\endgroup$
6
$\begingroup$

I was asked to write a function that does this

What is probably wanted is something that can be re-used on different inputs. Your variable listToRules is "fixed". Someone would need to assign values to a and x1 and so forth to be able to re-use it. The typical way to do this would look something like this:

makeRules[keys_, values_] := Thread[keys -> values]

And you could use it like this:

makeRules[{x1, x2, x3, x4}, {a, b, c, d}]

{x1 -> a, x2 -> b, x3 -> c, x4 -> d}

But now, you can use it on other inputs:

makeRules[{a, b, c}, {21, 22, 23}]

{a -> 21, b -> 22, c -> 23}

As an aside, this particular function definition isn't very robust, because lists have to satisfy certain criteria for Thread to work, but I doubt that fixing that issue is part of the assignment.

a function RulesTolist[rule1] that extracts and returns the two lists from a substitution list.

Fortunately, Mathematica has some nice, built-in functions for dealing with structures involving Rule, specifically Values and Keys. I think you should try to solve this on your own first, so look in the documentation for those functions. If you need help, show us what you tried. But the pattern you'll use for defining this function will be:

RulesTolist[rules_] := <...figure out what goes here...>
$\endgroup$
7
  • $\begingroup$ I thought of doing the following: defining a function that takes 3 arguments as variable: a list, anotherr list and another one which is the dimension of the list. Then I think of a for loop where I use Thread between every two corresponding elements of the lists. But I don't know how or whether is possible to give lists as arguments $\endgroup$
    – imbAF
    Jan 2 at 19:47
  • $\begingroup$ Have you programmed in C? That's a very C-like approach. You can get the length of a list directly from the list itself, so no need to add that length/dimension argument. But if you're going to use Thread, then you've already solved the problem (other than just turning it into a function, and I demonstrated how to do that above). But regardless, you certainly don't need For. So, is your question really about how to implement the function without Thread? $\endgroup$
    – lericr
    Jan 2 at 20:05
  • $\begingroup$ yes, that's the goal. Creating a function which does what Thread does. But another member already answered that. I find all this odd. To me, being asked to write codes in mathematica, is like: I just learned the alphabet in french and now I have to write a political article. I am entirely clueless. And I find writing codes in long lines, with multiple different types of brackets, very hard to read and understand $\endgroup$
    – imbAF
    Jan 2 at 20:16
  • $\begingroup$ And yeah, I have programmed in C,C++ and Python and all are relatively easier the mathematica. I don't have the slightest clue here. The language is so heavenly symbolic $\endgroup$
    – imbAF
    Jan 2 at 20:20
  • 5
    $\begingroup$ So I get that you're frustrated, but that's like the third time you've sort of ragged on Mathematica. No one here is forcing you to use it. If you'd like some insights on why the langauge is like it is, what its strengths are, how to "translate" from C to MMA, or help with specific constructs, we'd be happy to help. $\endgroup$
    – lericr
    Jan 2 at 20:39
5
$\begingroup$

Using Table:

rulesToList[k1_List, k2_List] := 
 Table[k1[[i]] -> k2[[i]], {i, Length@k1}]

xlist = {x1, x2, x3, x4};
vlist = {a, b, c, d};

rulesToList[xlist, vlist]

Using MapThread:

MapThread[Rule, {xlist, vlist}]

Using Transpose:

Rule @@@ Transpose[{xlist, vlist}]

You can convert the last two to functions as an exercise.


Result:

{x1 -> a, x2 -> b, x3 -> c, x4 -> d}

$\endgroup$
1
  • $\begingroup$ (+1) and loved the fact that you gave homework :-) $\endgroup$
    – bmf
    Jan 3 at 1:12
5
$\begingroup$

Some more ways of doing it in the hopes that it will get you motivated to look up the commands on the documentation

With

vars = {x1, x2, x3, x4};
rules = {a, b, c, d};

We begin by

AssociationThread[vars, #] &@rules // Normal

Another one

GeneralUtilities`AssociatePairs[Transpose[{vars, #}]] &@rules // Normal

Third one

Table[Outer[Rule, vars, rules, 1][[i, i]], {i, 1, 4}]

And another

MapThread[Rule, {vars, #}] &@rules

Final

MapThread[#1 -> #2 &, {vars, #}] &@rules

all of the above return

{x1 -> a, x2 -> b, x3 -> c, x4 -> d}

$\endgroup$
5
$\begingroup$

Inner is another possibility:

Inner[Rule,{x1, x2, x3, x4} , {a, b, c,d},List]

(* {x1 -> a, x2 -> b, x3 -> c, x4 -> d} *) 

Or with Dot:

List@@Rule@@@({x1, x2, x3, x4}.{a, b, c,d})

(* {x1 -> a, x2 -> b, x3 -> c, x4 -> d} *) 

The above is probably better written as:

Composition[Apply[List],MapApply[Rule],Dot][{x1, x2, x3, x4},{a, b, c,d}]

(* {a -> x1, b -> x2, c -> x3, d -> x4} *) 

To get back the original lists from a list of rules:

{#[[All,1]], #[[All,2]]}&@%

{{a, b, c, d}, {x1, x2, x3, x4}}
$\endgroup$
5
$\begingroup$

Just for fun:

rulethread = Block[{Rule}, SetAttributes[Rule, Listable]; #] &;

rulestolist = Block[{Rule = List}, #\[Transpose]] &;

{x1, x2, x3, x4} -> {a, b, c, d} // rulethread
(* {x1 -> a, x2 -> b, x3 -> c, x4 -> d} *)

{x1 -> a, x2 -> b, x3 -> c, x4 -> d} // rulestolist
(* {{x1, x2, x3, x4}, {a, b, c, d}} *)
$\endgroup$
1
  • $\begingroup$ wonderful use of Block!!! $\endgroup$
    – bmf
    Jan 3 at 12:05
2
$\begingroup$

The assignment is about writing one's first function. We are making this quite more complex than needed.

Mathematica offers two ways to write functions.

function[parameter1_, parameter2_]:=(function of parameter1 and parameter 2)

creates a named function that you can then apply to any parameters that you pass to it when you call it, for example

function[{a,b,c,d},{x1,x2,x3,x4}]

The various answers that offer different listsToRules functions offer solutions on that spirit.

A different type of function that mathematica offers is called a pure function and it uses slots marked by # and must end with &. Then you can apply this pure function on a list with /@, which is the abbreviation for Map. The answers that create a matrix out of the two lists may use this construction, although Syed's Rule@@@Transpose[{xlist, vlist}] skips the step of creating the function and takes advantage of the fact that Rule automatically gets mapped. the more explicit way to do this with a pure function would be

Rule @@ # & /@ Transpose[{xlist, vlist}]

What comes before the /@ gets applied to each member of the transposed matrix of the two lists. The first element, for example, is {x1,a}. The # picks that list up. But Rule@{x1,a} or (the equivalent) Rule[{x1,a}] produces an error because Rule wants two parameters and you are giving it one list as one parameter. The @@ replaces the braces of the list with Rule[] so that the result becomes Rule[x1,a]. I hope this helps. Mathematica is extremely powerful but has a steep learning curve. By the way, this a good time to adopt the formatting convention of never using uppercase for the items you define so as to avoid clashes with built-in symbols. Replace L1 and L2 with list1 and list2.

$\endgroup$
2
  • 1
    $\begingroup$ (+1) But aren't (1) Rule@@#&/@Transpose[{{a,b,c,d},{x1,x2,x3,x4}}], (2) Apply[Rule]/@Transpose[{{a,b,c,d},{x1,x2,x3,x4}}] and (3) MapApply[Rule]@Transpose[{{a,b,c,d},{x1,x2,x3,x4}}] all equivalent? (As is Composition[MapApply[Rule],Transpose, List][{a,b,c,d},{x1,x2,x3,x4}]), and (the new) MapApply is surely more intuitively obvious that the (ugly?) @@@ syntax? $\endgroup$
    – user1066
    Jan 3 at 16:42
  • $\begingroup$ I don't have an aesthetic opinion about what of all these is pretty. For my limited brain, Rule@#/@Transpose[{xlist,vlist}] would be the most pretty due to being the most intuitive, but it does not work. So, it has to be tweaked to Rule@@.... $\endgroup$
    – Nicholas G
    Jan 4 at 3:00

Your Answer

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

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