I use the following reusable expression to turn a list of items into a two-dimensional matrix. Then two nested foreaches to display it.
The number can be calculated somewhat (Not tested, out of my head) like:
(sizeOuterList * (outerIndex - 1)) + innerIndex
-----------
Rule inputs:
- items (Any)
- segmentSize (Integer)
- rotate (Boolean)
- enablePadding (Boolean)
if(
or(
a!isNullOrEmpty(ri!items),
a!isNullOrEmpty(ri!segmentSize)
),
ri!items,
a!localVariables(
local!numSegments: ceiling(count(ri!items) / ri!segmentSize),
if(
ri!rotate,
/* WITH ROTATION: segmentSize means the number of segments */
if(
ri!enablePadding,
/* WITH PADDING: Adds type casted NULL values to the last segment to fill up to the size of the segment */
a!forEach(
items: enumerate(ri!segmentSize),
expression: index(
ri!items,
1 /* First item in list is at index 1 and enumerate creates numbers starting at 0 */
+ fv!item /* Start number for current segment */
/* Fix segment size */
+ enumerate(local!numSegments)
* ri!segmentSize,
cast(runtimetypeof(ri!items[1]), null)
)
),
/* WITHOUT PADDING: Only add left over items into the last segment. The last segment might contain less items */
a!forEach(
items: enumerate(ri!segmentSize),
expression: reject(
a!isNullOrEmpty(_),
index(
ri!items,
1 /* First item in list is at index 1 and enumerate creates numbers starting at 0 */
+ fv!item /* Start number for current segment */
/* Adjust the size of the segment to either the required size or for the last segment the left over items */
+ enumerate(local!numSegments)
* ri!segmentSize,
null
)
)
)
),
/* WITHOUT ROTATION: segmentSize means the number of items per segment */
if(
ri!enablePadding,
/* WITH PADDING: Adds type casted NULL values to the last segment to fill up to the size of the segment */
a!forEach(
items: enumerate(local!numSegments),
expression: index(
ri!items,
1 /* First item in list is at index 1 and enumerate creates numbers starting at 0 */
+ (fv!item * ri!segmentSize) /* Start number for current segment */
/* Fixe segment size */
+ enumerate(ri!segmentSize),
cast(runtimetypeof(ri!items[1]), null)
)
),
/* WITHOUT PADDING: Only add left over items into the last segment. The last segment might contain less items */
a!forEach(
items: enumerate(local!numSegments),
expression: index(
ri!items,
1 /* First item in list is at index 1 and enumerate creates numbers starting at 0 */
+ (fv!item * ri!segmentSize) /* Start number for current segment */
/* Adjust the size of the segment to either the required size or for the last segment the left over items */
+ enumerate(min(ri!segmentSize, count(ri!items) - (fv!item * ri!segmentSize))),
null
)
)
)
)
)
)