2
$\begingroup$

When I use

Do[Print[{a, b}],{a, 0, 2},{b, 0, 2}]

then I (correctly) obtain

{0, 0} {0, 1} {0, 2} {1, 0} {1, 1} {1, 2} {2, 0} {2, 1} {2, 2}

However, I would like something like:

{0, 0} {0, 1} {1, 0} {0, 2} {1, 1} {2, 0} {1, 2} {2, 1} {2, 2}

That is, I want to prioritize calculations for which $a+b$ is small.

Is there any simple way to achieve this within the Do Command?

$\endgroup$
  • 3
    $\begingroup$ Maybe Do[Print[{a, t - a}], {t, 0, 4}, {a, Max[0, t - 2], Min[t, 2]}]? $\endgroup$ – Carl Woll May 25 '17 at 23:10
  • 1
    $\begingroup$ @CarlWoll Interesting approach, that is really helpful. Note that it generalizes to more variables by Do[Print[{a, s - a, t - s}], {t, 0, 6}, {s, Max[0, t - 2], Min[t, 4]}, {a, Max[0, s - 2], Min[s, 2]}], Do[Print[{a, s - a, t - s, u - t}], {u, 0, 8}, {t, Max[0, u - 2], Min[u, 6]}, {s, Max[0, t - 2], Min[t, 4]}, {a, Max[0, s - 2], Min[s, 2]}] etcetera $\endgroup$ – Uncountable May 26 '17 at 9:20
2
$\begingroup$

In my opinion, this doesn't seem like a very natural action to take with Do, which requires a fixed iterator specification.

Rather, you can construct a list with Table (note that the syntax is very similar to Do) :

Table[{a, b}, {a, 0, 2}, {b, 0, 2}]

{{{0, 0}, {0, 1}, {0, 2}}, {{1, 0}, {1, 1}, {1, 2}}, {{2, 0}, {2, 1}, {2, 2}}}

You can convert this to a list of tuples with Flatten:

Flatten[%, 1]
{{0, 0}, {0, 1}, {0, 2}, {1, 0}, {1, 1}, {1, 2}, {2, 0}, {2, 1}, {2, 2}}

Then sort it according to the sum of the list elements:

sortedList = SortBy[%, Total]
{{0, 0}, {0, 1}, {1, 0}, {0, 2}, {1, 1}, {2, 0}, {1, 2}, {2, 1}, {2, 2}}

Finally, you can iterate over the elements in this list using Scan :

Scan[Print, %]

Edit : It's worth mentioning that it's possible to use Do rather than Scan in the last line, but Scan is really a better fit here.

If you insist upon using Do, you can do

Do[Print[x], {x, sortedList}]
$\endgroup$
  • 1
    $\begingroup$ Thanks for your reply. I will consider this, however I do not really like the idea of a possibly large sortedList sitting inside my ram. $\endgroup$ – Uncountable May 26 '17 at 9:22
2
$\begingroup$

You can generate zig-zag ordered indices dynamically, without generating all possible values first.

Here is a simple zig-zag algorithm adopted from this SO answer. It should be optimized if the speed is a concern.

Function zigZagOrdering converts an integer index (from 0 to lengthA*lengthB-1) into the values of a (from 0 to lengthA-1) and b (from 0 to lengthB-1).

ClearAll[zigZagOrdering];
zigZagOrdering = Compile[{{lengthA, _Integer}, {lengthB, _Integer}, {index, _Integer}},
Module[{dx = 1, dy = -1, a=0, b=0},
    Do[
        a = a + dy;
        b = b + dx;
        If[a<0||b<0||a>=lengthA||b>=lengthB, {dx,dy} = {dy,dx}];
        If[a>=lengthA, a=lengthA-1; b=b+2];
        If[b>=lengthB, b=lengthB-1; a=a+2];
        If[a<0, a=0];
        If[b<0, b=0],
        {i, 0, index-1}];
    {a,b}
    ]]

This function can be used as follows:

Module[{lengthA=3, lengthB=3, a, b},
    Do[
        {a,b} = zigZagOrdering[lengthA, lengthB, index];
        Print[{a,b}],
        {index, 0, lengthA*lengthB-1}
        ];
    ]
{0,0}, {0,1}, {1,0}, {2,0}, {1,1}, {0,2}, {1,2}, {2,1}, {2,2}
$\endgroup$
1
$\begingroup$

If you do not mind ultimately over a slightly bigger domain. (For example if you plan on aborting at some stage anyway) you can simply redefine you indices A=a+b and b

Do[Print[{A-b,b}],{A,0,4},{b,0,2}]

if you want to restrict to the same square domain

Do[Print[{(A-b),b}],{A,0,4},{B, Max[0,A-2] , Min[2,A]}]
$\endgroup$
  • $\begingroup$ I very much like this method's simplicity, but I think it needs some refinement. The first code can be vastly improved by replacing {B,-A,A} with {B,-A,A,2} -- this eliminates all the fractions. (As a bonus, you can restrict to exactly the desired output by checking that a<=2&&b<=2 in the body of Do.) Moreover, your second method doesn't work. It misses {2,0}, for example. $\endgroup$ – jjc385 May 26 '17 at 17:23
  • $\begingroup$ corrected the bounds. Works perfectly now $\endgroup$ – mmeent May 26 '17 at 20:28
  • $\begingroup$ You still need to replace B with b in the iterator specification for your second method. $\endgroup$ – jjc385 May 27 '17 at 0:13
  • $\begingroup$ It's worth mentioning that the second method is now extremely similar to CarlWoll's comment. $\endgroup$ – jjc385 May 27 '17 at 0:21
0
$\begingroup$
all[{i_Integer}] := Sequence @@ {{0, i}, {i, 0}}
all[{i_Integer, i_Integer}] := {i, i}
all[{i_Integer, j_Integer}] := Sequence @@ {{i, j}, {j, i}}
Do[Print /@ all /@ IntegerPartitions[i, 2, Range[3]], {i, 1, 7}]

enter image description here

$\endgroup$
0
$\begingroup$
SortBy[Tuples[Range[0, 2], 2], Total]

{{0, 0}, {0, 1}, {1, 0}, {0, 2}, {1, 1}, {2, 0}, {1, 2}, {2, 1}, {2,2}}
$\endgroup$
0
$\begingroup$

Take your list and then:

SortBy[mylist, Norm]
$\endgroup$
  • $\begingroup$ Reasonable approach that gives {{0, 0}, {0, 1}, {1, 0}, {0, 2}, {2, 0}, {1, 1}, {2, 2}, {1, 2}, {2, 1}}. Similar but not identical to what was suggested in the question. $\endgroup$ – bbgodfrey May 27 '17 at 0:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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