# ConcatRows

### ConcatRows(a, i, j, k)

Flattens array «a» by replacing the two indexes «i» and «j» by a single new index «k» that includes all combinations of values from «i» and «j». If you don't specify «i», it generates a local index with the name .ConcatIndex, containing all those combinations. If you do specify «i», it must have length equal to Size(i)*Size(j).

### Examples

Let

Variable A:=
J ▶
I ▼ 1 2 3 4
1 'a' 'b' 'c' 'd'
2 'e' 'f' 'g' 'h'

Then

ConcatRows(A, I, J) →
.ConcatIndex ▶
1 2 3 4 5 6 7 8
'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h'
ConcatRows(A, J, I) →
.ConcatIndex ▶
1 2 3 4 5 6 7 8
'a' 'e' 'b' 'f' 'c' 'g' 'd' 'h'

To flatten three dimensions, I1, I2 and I3, use:

Var tmp := ConcatRows(A, I1, I2) Do ConcatRows(tmp, tmp. ConcatIndex, I3)

### Inverse of ConcatRows

It is often useful to do the inverse of ConcatRows -- that is, unflatten a 1D array indexed by K to produce a 2D array indexed by I and J. As with ConcatRows, K must have Size(I)*Size(J) elements. You can do this by defining this function:

Function UnconcatRows(X: Array[K]; I, J, K: Index)
Definition: X[K = (@I - 1)*Size(J) + @J]

You can use this function to extend a variety of 1D transformation functions to their 2D equivalents. For example, Rank(X, I) returns the sort rank of each element in X. Given a 2D array, apply ConcatRows to flatten it, then apply the 1D transformation Rank() to the 1D result, and finally use UnConcatRows() to get back the 2D array of ranks:

Var B := ConcatRows(A, I, J);
LocalAlias K := Handle(B.ConcatIndex);
UnconcatRows(Rank(B, K), I, J, K)

Some other 1D transformation functions that can be usefully extended to 2D equivalents in this fashion are: Sort, Cumulate, Uncumulate, CumProduct, Dispatch, GetFract, Frequency. The technique could be applied to Integrate, Cdf, Pdf, LinearInterp and CubicInterp functions, but the results might not be quite the same as what you would normally think of as the 2D generalization of the functions, so use with care in those cases.