0
$\begingroup$

I wrote a program that is supposed to take a list (of arbitrary length) of pairs of the digits of binary numbers (e.g. list = {{{1,1,0,0},{0,0,1,1}},{{1,0,1,0},{0,1,0,1}}} and swap the elements to the left of a random position between the pairs via RandomInteger. For example, the program is supposed to take the first element of list, {{1,1,0,0},{0,0,1,1}}, produce a random integer between 1 and the length of the first or second sub-element in the list (let's say this random integer is 3) and swap the elements of each list of binary digits to the left of the third position to produce {{0,0,1,1},{1,1,0,0}}. The program then is supposed to continue with the second element in list, {{1,0,1,0},{0,1,0,1}}, produce another (potentially same) random number which will serve as the position where the elements to the left of each pair gets swapped.

From there, the program should finish off by producing the pairs with swapped elements in a list (i.e. {{{0,0,1,1},{1,1,0,0}}, ...}. When I ran it, it initially produced only the first pair of swapped binary digits. Then, after several attempts at fixing it, it wouldn't evaluate anything or produce Null. Needless to say, I'm stuck. Here's the program I wrote. I must admit that I only recently took up Mathematica programming as a hobby and I am not very experienced, so my program is likely not as streamlined as it could be. I have made attempts at learning of different Mathematica functions to make the code better, but thus far, this is what I've come up with. I don't mean to waste anyone's time due to my naiveté.

    BinarySwitch[a_] := Module[{},

    SetOfNewBinary = {};
    For[x = 1, x <= Length[a], x++,
     NewBinarySet = {};
     NewBinary1 = {};
     NewBinary2 = {};
     pos1 = a[[x]][[1]];
     pos2 = a[[x]][[2]];
     ri = RandomInteger[{1, Length[pos1] - 1}];
     Print[ri];
      For[y = 1, y < ri, y++,
       rp1 = ReplacePart[pos1, i -> pos2[[y]]];
       rp2 = ReplacePart[pos2, i -> pos1[[y]]];
       position1 = rp1[[y]];
       position2 = rp2[[y]];
       NewBinary1 = Append[NewBinary1, position1];
       NewBinary2 = Append[NewBinary2, position2];
      ];
      For[z = ri, z <= Length[pos1], z++,
       NewBinary1 = Append[NewBinary1, pos1[[z]]];
       NewBinary2 = Append[NewBinary2, pos2[[z]]];
      ];
    NewBinarySet = Append[NewBinarySet, NewBinary1];
    NewBinarySet = Append[NewBinarySet, NewBinary2];
    Print[NewBinarySet];
   ];
  SetOfNewBinary = Append[SetOfNewBinary, NewBinarySet];
  Print[SetOfNewBinary];
  ];

Many thanks in advance.

$\endgroup$
4
  • $\begingroup$ There are several interpretations of "swap" that lead to the same result - do you mean taking the "digits" to the left of n and "swapping" them by putting them behind the rest of the digits for each sublist? $\endgroup$
    – ciao
    Commented Jun 6, 2015 at 23:35
  • $\begingroup$ Somewhat along those lines, but to be more specific, let's say I'm working with {a,b,c,d} and {e,f,g,h}. RandomInteger will produce an integer between 1 and the length of either of those two lists. This number will pertain to a position. Let's say that it produces 4. Then it will take the elements to the left of d in {a,b,c,d} and the elements to the left of h in {e,f,g,h} and put them at the front of the other list to produce {e,f,g,d} and {a,b,c,h} in that order. Now, I want to be able to put in a list of pairs and have the program do this for every pair in the list. $\endgroup$
    – Gary1234
    Commented Jun 6, 2015 at 23:50
  • $\begingroup$ Welcome to Mathematica.SE! I suggest the following: 1) As you receive help, try to give it too, by answering questions in your area of expertise. 2) Read the faq! 3) When you see good questions and answers, vote them up by clicking the gray triangles, because the credibility of the system is based on the reputation gained by users sharing their knowledge. Also, please remember to accept the answer, if any, that solves your problem, by clicking the checkmark sign! $\endgroup$
    – Michael E2
    Commented Jun 7, 2015 at 0:04
  • $\begingroup$ Yet another genetic algorithm crossover code request? $\endgroup$
    – m_goldberg
    Commented Jun 7, 2015 at 22:36

2 Answers 2

3
$\begingroup$

I think this is what you're after. I assumed the sublist pairs are all same length...

list = {{{a, b, c, d}, {e, f, g, h}}, {{i, j, k, l}, {m, n, o, p}}}

MapThread[Module[{l = #}, l[[{1, 2}, ;; #2]] = l[[{2, 1}, ;; #2]]; l] &, 
                 {list,RandomInteger[Length@list[[1, 1]] - 1, Length@list]}]

(* {{{a, b, c, d}, {e, f, g, h}}, {{m, n, k, l}, {i, j, o, p}}} *)

(so in that example, the random numbers were 1 and 3... )

If that is correct, comment and I'll happily break it down / explain it, else I'll delete.

Explanation:

MapThread[f,l] - this takes a list l and walks through its elements, applying some function/operation f to each set, and resulting in a list of results. When the list is a list of lists (the intended use case), it walks over each element of each list, giving f access to the set of those elements.

So, for example:

MapThread[Plus,{{1,2,3},{4,5,6}}]

Gives

(* {5,7,9} *)

Since 1+4=5, 2+5=7...

Within a pure function f, the individual members of each set can be accessed with the shorthand # (or #1), #2, #3... for the first, second, third... of each set.

So here, #1 would take on 1,2,3 as MapThread walks, and #2 would take on 4,5,6 in the example. We don't need to specifically reference them with Plus - but for our specific swapping function, we do (and there will be two arguments - the pair and some random number), so...

Our function is:

Module[{l = #}, l[[{1, 2}, ;; #2]] = l[[{2, 1}, ;; #2]]; l] &

This way of defining a function is called a "pure function" - there are other ways that you can learn about in the documentation and tutorials here. Let's take it apart...

Module is a mechanism for defining "local" information, so we're saying make a local symbol called l that gets the first of each set from the MapThread. Using module ensures it won't clobber some l that might be defined elsewhere.

If you look at the whole function, we see the list used in our MapThread is {list, RandomInteger[Length@list[[1, 1]] - 1, Length@list]} - so, it's a list of two lists, the first is your target list, the second is a set of random numbers (we'll get to that shortly).

So, the l will take on each set of pairs as we go through the target. We need to do this because you can't operate (swap/assign) to an argument (#) directly.

The next bit of our function l[[{1, 2}, ;; #2]] = l[[{2, 1}, ;; #2]]; says "take the first and second of the pairs, up to some position (#2), make them equal to the second and first of the pairs up to that same position...". So, l[[{1,2}]] just means "give me the first and second in l as a list", and l[[{1,2},;;x]] means "give me the first and second in l, each up to position x as a list".

By swapping the {1,2} and {2,1}, we get what we wanted.

Finally, we end the function with l, resulting in the result of the swap getting output as that element of the result list.

The second member of the MapThread is the RandomInteger[Length@list[[1, 1]] - 1, Length@list].

Here, we say "give me a list of random numbers of the length of the target (Length@list), between 0 and the length of the sublists-1 (Length@list[[1, 1]] - 1 says give me the length of the first sublist's first list - my assumption here of equal lengths).

I do it that way since we want to swap positions left of some number 1 to length of lists, which is equivalent to just taking parts from up to 0 (nothing) to some number of positions.

That's about it, if not crystal, let me know...

$\endgroup$
3
  • $\begingroup$ Wow! Yes! That's what I was looking for. Can you please explain? $\endgroup$
    – Gary1234
    Commented Jun 7, 2015 at 0:10
  • $\begingroup$ @Gary1234: OK, give me a moment, I'll add explanation... $\endgroup$
    – ciao
    Commented Jun 7, 2015 at 0:12
  • $\begingroup$ That explanation was absolutely beautiful. I cannot thank you enough! $\endgroup$
    – Gary1234
    Commented Jun 7, 2015 at 0:53
1
$\begingroup$

Here are a couple of methods to swap the elements of the first n columns of an array l of two lists,

swap[l_, n_] := Transpose@MapAt[Reverse, Transpose@l, ;; n];

or

swap[l_, n_] := Join[Reverse[l[[All, ;; n]]], l[[All, n + 1 ;;]], 2];

Example (ciao's data):

list = {{{a, b, c, d}, {e, f, g, h}}, {{i, j, k, l}, {m, n, o, p}}};
MapThread[swap, {list, {1, 3}}]
(*  {{{e, b, c, d}, {a, f, g, h}}, {{m, n, o, l}, {i, j, k, p}}}  *)

In general, like ciao's,

MapThread[swap, {list, RandomInteger[{1, Length@list[[1, 1]]}, Length@list]}]
$\endgroup$
1
  • $\begingroup$ I seldom remember MapAt accepts spans... +1 $\endgroup$
    – ciao
    Commented Jun 7, 2015 at 4:17

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.