How to generate this structure of a list without `While` and the like?
Whenever you're building a list with While
or For
, there's a good chance Table
or Array
can help. In this case, the solution with Table
is quite simple: just use two iterators and make the bounds of the second dependent on the first iterator:
list[d_] := Join @@ Table[i*d + j, {i, 0, d}, {j, i + 1, d}]
The Join @@
is used to flatten the array. Flatten @
would also do, but I prefer the former when I know that I'm only flattening one level.
As you noted this is quite a bit slower than your own solution. If performance is a concern, you can use this slightly less readable form that combines Table
with Range
and appears to be about 10 to 20 times faster than your code:
list[d_] := Join @@ Table[Range[i*d + i + 1, (i + 1) d], {i, 0, d}]
This works:
f[d_] := Join @@ MapThread[
Range,
Transpose@Table[{(i - 1) d + i, i d}, {i, d}]
];
so
f[3]
{1, 2, 3, 5, 6, 9}
and it's pretty fast as well:
AbsoluteTiming[f[10000];]
{0.410494, Null}
same caveat about Join@@
vs Flatten@
as Martin Büttner by whose wise comment this can be simplified to merely:
f[d_] := Join @@ Range @@@ Table[{(i - 1) d + i, i d}, {i, d}]
different ... but slow :)
f1 = SparseArray[UpperTriangularize[Partition[Range[#^2], #]]][ "NonzeroValues"] &
f1 /@ {3, 4}
{{1, 2, 3, 5, 6, 9},
{1, 2, 3, 4, 6, 7, 8, 11, 12, 16}}
Also different but slower:
f2 = Flatten[UpperTriangularize[Partition[Range[#^2], #]] /. 0 -> (## &[])] &
f3 = Sort[SparseArray[{i_, j_} /; i <= j :> (i - 1) # + j, {#, #}]["NonzeroValues"]] &;
f1 /@ {3, 4} == f2 /@ {3, 4} == f3 /@ {3, 4}
True