# Source code for simplestatistics.statistics.product

"""
Implements product() function.
"""

[docs]def product(x, y):
"""
This function calculates the product of two vectors or lists of numerical objects, like so:

.. math::
[x_1, x_2, x_3, x_4] \\times [y_1, y_2, y_3, y_4] = [x_1y_1, x_2y_2, x_3y_3, x_4y_4]

Args:
x: An int or a float, or a list or tuple of numerical objects.
y: An int or a float, or a list or tuple of numerical objects. If a\
list or tuple, must have the same length as x.

Returns:
A list of numerical objects of the same length as x and y.

Examples:

>>> product([1, 2, 3], [1, 2, 3])
[1, 4, 9]
>>> product((2, 3), (3, -1))
[6, -3]
>>> product([1.25, 2.75], [2.5, 3.40])
[3.125, 9.35]
>>> product(2, [1, 2, 3])
[2, 4, 6]
>>> product([-3, -2, -1], 3)
[-9, -6, -3]
>>> product(5.5, 6.4)
35.2

>>> product('a', [2, 4])
Traceback (most recent call last):
...
TypeError: product() expects ints, floats, lists, or tuples of numbers.
>>> product([1, 2], [3, 4, 5])
Traceback (most recent call last):
...
ValueError: The two lists or tuples have to have equal lengths
"""
# product can work with two list, two tuples, two ints,
# or an int and one of the others
if type(x) not in [int, float, list, tuple] or type(y) not in [int, float, list, tuple]:
raise TypeError('product() expects ints, floats, lists, or tuples of numbers.')

# if you provide lists or tuples, they have to have the same length
# for now
if type(x) in [list, tuple] and type(y) in [list, tuple] and len(x) != len(y):
raise ValueError('The two lists or tuples have to have equal lengths')

product_vector = []

# I'm not very happy with this if-else heavy implementation
# but can't think of how to do this in a smarter more dynamic way

# if both are ints, return their product
if type(x) in [int, float] and type(y) in [int, float]:
return(x * y)

# if x is int, y must be a float, list, or tuple
elif type(x) in [int, float]:
for ii, _ in enumerate(y):
product_vector.append(x * y[ii])

# if y is int, x must be a float, list, or tuple
elif type(y) in [int, float]:
for ii, _ in enumerate(x):
product_vector.append(x[ii] * y)

# else, both are lists or tuples
else:
for ii, _ in enumerate(x):
product_vector.append(x[ii] * y[ii])

return(product_vector)