Skip to content

capturegraph.data.containers.utilities.outer #

outer - Cartesian Product for Lists#

Create all combinations of items from multiple Lists, returning a multi-dimensional nested List structure. Similar to zip(), but creates the outer product instead of zipping element-wise.

Example
import capturegraph.data as cg

# Create all location/time combinations
locations = cg.List([loc_a, loc_b])
times = cg.List([t1, t2, t3])

# Outer product: 2x3 nested list
combos = cg.outer(location=locations, time=times)
# → List([
#     List([{location: loc_a, time: t1}, {location: loc_a, time: t2}, {location: loc_a, time: t3}]),
#     List([{location: loc_b, time: t1}, {location: loc_b, time: t2}, {location: loc_b, time: t3}]),
#   ])

# Flatten for 1D iteration
flat = cg.flatten(combos)
# → List([{location: loc_a, time: t1}, {location: loc_a, time: t2}, ...])
Positional Arguments

Like zip(), outer() also supports positional arguments which are accessed by index:

cg.outer([1, 2], ['a', 'b'])
# → List([
#     List([{0: 1, 1: 'a'}, {0: 1, 1: 'b'}]),
#     List([{0: 2, 1: 'a'}, {0: 2, 1: 'b'}]),
#   ])

outer(*args, **kwargs) #

Create a Cartesian product of Lists as nested List of Dicts.

Creates a multi-dimensional nested List structure where the nesting depth equals the number of arguments, and each leaf is a Dict with all the combined values.

Parameters:

Name Type Description Default
*args T | List[T]

Positional Lists (accessed by index 0, 1, 2, ...).

()
**kwargs T | List[T]

Named Lists (accessed by name).

{}

Returns:

Type Description
List[Any]

Nested List of Dicts. The nesting corresponds to each input List,

List[Any]

in the order provided.

Raises:

Type Description
ValueError

If no arguments are provided.

Example
# 2D grid of location/time combinations
grid = cg.outer(location=locations, time=times)

# Access: grid[loc_idx][time_idx].location, .time
cell = grid[0][1]  # First location, second time

# Flatten for sequential processing
all_combos = cg.flatten(grid)
Source code in capturegraph-lib/capturegraph/data/containers/utilities/outer.py
def outer[T](*args: T | List[T], **kwargs: T | List[T]) -> List[Any]:
    """Create a Cartesian product of Lists as nested List of Dicts.

    Creates a multi-dimensional nested List structure where the nesting
    depth equals the number of arguments, and each leaf is a Dict with
    all the combined values.

    Args:
        *args: Positional Lists (accessed by index 0, 1, 2, ...).
        **kwargs: Named Lists (accessed by name).

    Returns:
        Nested List of Dicts. The nesting corresponds to each input List,
        in the order provided.

    Raises:
        ValueError: If no arguments are provided.

    Example:
        ```python
        # 2D grid of location/time combinations
        grid = cg.outer(location=locations, time=times)

        # Access: grid[loc_idx][time_idx].location, .time
        cell = grid[0][1]  # First location, second time

        # Flatten for sequential processing
        all_combos = cg.flatten(grid)
        ```
    """
    if not args and not kwargs:
        raise ValueError("outer requires at least one argument")

    # Combine args and kwargs into ordered dict
    combined = {f"{i}": v for i, v in enumerate(args)} | kwargs
    keys = list(combined.keys())
    values = list(combined.values())

    # Normalize to lists
    lists = []
    for v in values:
        if isinstance(v, (list, List, tuple)):
            lists.append(list(v))
        else:
            lists.append([v])

    if len(lists) == 0:
        return List([])

    # Build nested structure recursively
    def build_nested(depth: int, indices: tuple) -> Any:
        if depth == len(lists):
            # Leaf: create Dict with all values
            row_data = {keys[i]: lists[i][idx] for i, idx in enumerate(indices)}
            return Dict(row_data)
        else:
            # Non-leaf: create List for this dimension
            return List(
                [
                    build_nested(depth + 1, indices + (i,))
                    for i in range(len(lists[depth]))
                ]
            )

    return build_nested(0, ())