Related to MrZizoScream's Product Array kata. You might want to solve that one first :)

```if:javascript
**Note:** Node 10 has now been enabled, and you can now use its BigInt capabilities if you wish, though your resulting array must still contain strings (e.g. "99999999999", not 9999999999n)

Pre-node 10: You will need to use the BigNumber.js library! Please use `.toFixed(0)` or `.toPrecision()` to round instead of `.toString(10)`, as the latter is _very_ slow
```

This is an adaptation of a problem I came across on LeetCode. 

Given an array of numbers, your task is to return a new array where each index (`new_array[i]`) is equal to the product of the original array, except for the number at that index (`array[i]`).

**Two things to keep in mind:**

* Zeroes will be making their way into some of the arrays you are given
* O(n^2) solutions will not pass.

Examples:

**Note**: All inputs will be valid arrays of nonzero length.

Have fun! Please upvote if you enjoyed :)

Difficulty: introductory

Starter code:

def product_sans_n(nums):
	

Solutions:
from functools import reduce

def product_sans_n(nums):
    z = nums.count(0)
    if z > 1: return [0] * len(nums)
    
    p = reduce(int.__mul__, (v for v in nums if v))
    return [not v and p for v in nums] if z else [p//v for v in nums]

from functools import reduce


def product_sans_n(nums):
    z, p = nums.count(0), reduce(int.__mul__, (n for n in nums if n))
    return [0 for _ in nums] if z > 1 else [0 if n else p for n in nums] if z else [p // n for n in nums]

from functools import reduce
from operator import mul

def mulsum(xs):
    return reduce(mul, xs, 1)

def product_sans_n(nums):
    nz = nums.count(0)
    if nz > 1:
        return [0] * len(nums)
    elif nz:
        return [0 if x else mulsum([_f for _f in nums if _f]) for x in nums]
    xs = mulsum(nums)
    return [xs // x for x in nums]


from functools import reduce
# Since it must be less thatn O(n^2) the solution may not involve mul(Array[:]) for each
# element of Array since mul would be O(n-1) and you would do O(n) calls to mul.
    
# Since it must be less thatn O(n^2) the solution may not involve mul(Array[:]) for each
# element of Array since mul would be O(n-1) and you would do O(n) calls to mul.
    
# The only way that occurs to me is calling mul just once [that is O(n)] and then mapping / on the
# result Array [that is another O(n)], but since the calls are concatenated the final complexity
# is O(2n)

# Also, since 

def product_sans_n(nums):
    # The case for two or more zeros is trivial and can be handled separately:
    # Just a list of N zeroes where N is the length of nums
    if len([ x for x in nums if x == 0]) > 1:
        return [0] * len(nums)
    
    # Now, if there is only one zero this must be stripped from the product P
    # The product can be computed by the functool reduce: this is O(n)
    from operator import mul
    from functools import reduce
    onezero = 0 in nums
    product = reduce(mul, nums if not onezero else nums[:nums.index(0)]+nums[nums.index(0)+1:])
    
    # Now, we iterate through the original list dividing the product P by each element
    # The case of one zero is handled separately
    # There is only one list traversing with map: this is O(n)
    if onezero:
        return list(map((lambda x: 0 if x != 0 else product), nums))
    else:
        return list(map((lambda x: product / x), nums))
    
    # In the end, the algorithm is O(2*n)


def product_sans_n(l):
    contains_zeroes = False
    product = 1
    for n in l:
        if n:
            product *= n
        elif not contains_zeroes:
            contains_zeroes = True
        else:
            return [0] * len(l)
    return [0 if n else product for n in l] if contains_zeroes else [product // n for n in l]

def product_sans_n(nums):
    zeros, product = 0, 1
    for n in nums:
        if n: product *= n
        else: zeros += 1
    return [zeros < 2 and
    (not n and product if zeros else product // n)
    for n in nums]

from operator import mul
from functools import reduce

def product_sans_n(nums):
    z = nums.count(0)
    p = 0 if z > 1 else reduce(mul, (x for x in nums if x != 0), 1)
    return [p//x if x != 0 and z == 0 else
            p    if x == 0 and z == 1 else
            0    for x in nums]

from functools import reduce

def product_sans_n(nums):
    s = set(nums)
    if 0 in s:
        return [ reduce(int.__mul__, nums[:i] + nums[i+1:]) for i, e in enumerate(nums) ]
    else: 
        prod = reduce(int.__mul__, nums)
        return [ prod//n  for n in nums]


from functools import reduce


def product_sans_n(nums):
    zero, prod = nums.count(0), reduce(int.__mul__, (n for n in nums if n))
    if zero:
        return [0 for _ in nums] if zero > 1 else [0 if n else prod for n in nums]
    return [prod // n for n in nums]

from itertools import accumulate, chain, islice
from operator import mul

def product_sans_n(nums):
    forward = islice(accumulate(chain([1], nums), mul), 0, len(nums), 1)
    backward = list(accumulate(chain([1], reversed(nums)), mul))[-2::-1]
    return list(map(mul, forward, backward))


from functools import reduce
def product_sans_n(nums):
    if nums.count(0) > 1:
        return [0 for i in nums]
    elif nums.count(0) == 1:
        prod = reduce(lambda a, b: a*b, [x for x in nums if x!=0])
        return [0 if i != 0 else prod for i in nums]
    else:
        prod = reduce(lambda a, b: a*b, nums)
        return [prod//i for i in nums]


    #because the output is so huge, output is hidden for the medium and big random tests
    
import numpy  as np
def product_sans_n(nums):
        numLen = len(nums)
        leftProducts = [None for _ in range(numLen)]
        rightProducts = [None for _ in range(numLen)]
        leftRunningProduct = 1
        rightRunningProduct = 1
        for i in range(numLen):
            leftRunningProduct = leftRunningProduct * nums[i]
            leftProducts[i] = leftRunningProduct
            rightRunningProduct = rightRunningProduct * nums[numLen-1-i]
            rightProducts[numLen-1-i] = rightRunningProduct

        result = [None for _ in range(numLen)]
        for i in range(numLen):
            product = 1
            if i > 0:
                product = product * leftProducts[i-1]
            if i < numLen-1:
                product = product * rightProducts[i+1]
            result[i] = product
        return result


def product_sans_n(nums):
     p = 1
     zeroes = nums.count(0)
     for n in nums:
        if n:
            p *= n
     return [zeroes < 2 and (not n and p if zeroes else p // n) for n in nums ]


from functools import reduce

def product_sans_n(nums):
    zeroes = nums.count(0)
    if zeroes >= 2:
        return [0 for x in nums]
    elif zeroes == 1:
        prod = reduce(int.__mul__, (x for x in nums if x != 0))
        return [0 if x != 0 else prod for x in nums]
    
    prod = reduce(int.__mul__, nums)
    return [prod // x for x in nums]


from functools import reduce
import operator

def product_sans_n(nums):
    prod = reduce(operator.mul, [x for x in nums if x != 0])
    zero_count = nums.count(0)
    for index,value in enumerate(nums):
        if value != 0 and zero_count != 0:
            nums[index] = 0
        elif value == 0 and zero_count > 1:
            nums[index] = 0
        elif value == 0:
            nums[index] = prod
        else:
            nums[index] = prod // value
    return nums

from functools import reduce

def product_sans_n(nums):
    if nums.count(0) > 1: return [0] * len(nums)
    if nums.count(0) == 1:
        i = nums.index(0)
        s = reduce(int.__mul__,nums[:i]+nums[i+1:])
    t = reduce(int.__mul__,nums)
    return [ s if x == 0 else t//x for x in nums ]

import itertools
import operator
def product_sans_n(l):
    r=[]
    p=list(itertools.accumulate(l,operator.mul))[-1]
    for i in range(len(l)):
       try:
           r.append(p//l[i])
       except:
           s=1
           for j in range(len(l)):
               if i!=j:
                   s*=l[j]
           r.append(s)        
               
    return r   

from functools import reduce

def product(q):
    return reduce(int.__mul__, q)

def product_sans_n(q):
    if any(not x for x in q):
        return [product(q[0:i]+q[i+1:]) for i, x in enumerate(q)]
    else:
        n = product(q)
        return [n//x for x in q]

from numpy import prod
def product_sans_n(n):
  if n.count(0)>1: 
    return [0 for _ in n]
  p=1
  for x in n:
    if x!=0: p*=x
  if n.count(0)==1:
    return [0 if x!=0 else p for x in n]
  return [p//x for x in n]

from operator import mul
from functools import reduce

def product_sans_n(numbers):
    check = reduce(mul, numbers)
    out = []
    
    if not check:
        for i in range(len(numbers)):
            c = reduce(mul,numbers[:i]+numbers[i+1:])
            out.append(c)

    else:
        for x in numbers:
            out.append(check//x)
            
    return out