Search code examples
pythonvariadic-functionskeyword-argument

Finction with nested loop and kwargs: how to invoke two lists one after another? (Cartesian product)


I'm trying to recreate itertools.product.

I know how to create a loop for this task, ex.:

arr1 = [1, 2, 3]
arr2 = [5, 6, 7]
arr_out = []

for i in arr1:
    for i1 in arr2:
        final = i, i1
        arr_out.append(final)
print(arr_out)

output:

[(1, 5), (1, 6), (1, 7), (2, 5), (2, 6), (2, 7), (3, 5), (3, 6), (3, 7)]

But I wonder how to create a function from that with kwargs. I try something like this:

arr1 = [1, 2, 3]
arr2 = [5, 6, 7]

def my_cool_product(**kwargs):
    
    arr_out = []
    
    for i in kwargs[0].items():
        for i1 in kwargs[1].items():
            final = i, i1
            arr_out.append(final)

print(my_cool_product(arr1, arr2))

But it doesn't work.

output:

TypeError: my_cool_product() takes 0 positional arguments but 2 were given

I don't know how to call each subsequent kwarg in a nested loop. I want to get the same output as in the first example.

The goal is to do it without importing any modules, like itertools, in other words, do it from scratch.


Solution

  • **kwargs is unfit for a function like the one you're proposing.

    As linked from in the comments, **kwargs is used for variadic keyword argument functions. In your case you're looking for any number of unnamed lists.

    Let's say there's only 2 arrays you're trying to get the product of, as you imply in your example function:

    def my_cool_product(**kwargs): 
        arr_out = []
        for i in kwargs["array1"]:
            for i1 in kwargs["array2"]:
                final = i, i1
                arr_out.append(final)
        return arr_out
    

    You may then use it like so:

    >>> my_cool_product(array1=[1,2,3], array2=[4,5,6])
    [(1, 4), (1, 5), (1, 6), (2, 4), (2, 5), (2, 6), (3, 4), (3, 5), (3, 6)]
    

    But since the names array1 and array2 are meaningless, using *args would be preferred:

    def my_cool_product(*args): 
        arr_out = []
        for i in args[0]:
            for i1 in args[1]:
                final = i, i1
                arr_out.append(final)
        return arr_out
    
    >>> my_cool_product([1,2,3], [4,5,6])
    [(1, 4), (1, 5), (1, 6), (2, 4), (2, 5), (2, 6), (3, 4), (3, 5), (3, 6)]
    

    For further supporting any number of lists, please see the duplicate questions, so as for the difference between *args and **kwargs.