Given a set of integers _S_, the _closure of S under multiplication_ is the smallest set that contains _S_ and such that for any _x, y_ in the closure of _S_, the product _x * y_ is also in the closure of _S_. 

Example 1: Given `S = {2}`, the closure of `S` is the set `{2, 4, 8, 16, 32, 64, ... }`.

Example 2: Given `S = {1, 2, 3}`, the closure of `S` is the set `{1, 2, 3, 4, 6, 8, 9, 12, 16, 18, 24, 27, 32, 36, ...}`. This set contains, e.g, `6` because `6 = 2 * 3`. It further contains `12` and `18` because `12 = 2 * 6` and `18 = 3 * 6`. Etc. 

Example 3: Given `S` the set of prime numbers, the closure of `S` is the set of all positive integers greater than or equal to `2`. 

Your task is two write a generator function that generates the members of the closure of any given _finite_ set of positive numbers `S` in _ascending order_.

Source: codewars | Difficulty: MEDIUM

Starter code: def closure_gen(*s):
	

Solutions:
from heapq import heappush, heappop

def closure_gen(*s):
	q = sorted(s)
	m = set(s)
	while q:
		curr = heappop(q)
		yield curr
		for i in s:
			t = curr * i
			if t not in m:
				heappush(q, t)
				m.add(t)


from heapq import *

def closure_gen(*s):
	(keys, seen) = (set(s), set(s))
	q = sorted(seen)
	while q:
		curr = heappop(q)
		for next in [v for v in [curr * i for i in keys] if not v in seen]:
			heappush(q, next)
			seen.add(next)
		yield curr


def closure_gen(*s):
	if not s:
		return
	if s[0] == 1:
		yield 1
		s = s[1:]
		if not s:
			return
	indices = {x: 0 for x in s}
	seq = [1]
	while True:
		m = float('inf')
		for (x, i) in indices.items():
			m = min(m, seq[i] * x)
		yield m
		seq.append(m)
		for (x, i) in indices.items():
			if seq[i] * x == m:
				indices[x] += 1


def closure_gen(*s):
	print(s)
	if s == ():
		return
	if s == (1,):
		yield 1
		return
	if len(s) == 1:
		(v0, vi) = (s[0], s[0])
		while True:
			yield vi
			vi *= v0
	s = list(s)
	for i in [0, 1]:
		if i in s:
			yield i
			s.remove(i)
	queue = [1]
	seen = set(queue)

	def next_value(i, si, rank):
		while True:
			val = queue[rank] * si
			if val in seen:
				rank += 1
				continue
			break
		seen.add(val)
		return (val, i, si, rank)
	queues = [next_value(i, si, 0) for (i, si) in enumerate(s)]
	while True:
		(vn, i, si, rank) = min(queues)
		queue.append(vn)
		yield vn
		queues[i] = next_value(i, si, rank + 1)


from heapq import heappush, heappop, heapify

def closure_gen(*s):
	if not s:
		return None
	set_s = set(s)
	heap_s = [i for i in s]
	heapify(heap_s)
	while set_s:
		current = heappop(heap_s)
		new_values = {current * i for i in s}.difference(set_s)
		for i in new_values:
			heappush(heap_s, i)
		set_s.update(new_values)
		set_s.discard(current)
		yield current


import heapq

def closure_gen(*s):
	if not s:
		raise StopIteration()
	h = set(s)
	q = list(h)
	heapq.heapify(q)
	if q == [1]:
		yield 1
		raise StopIteration()
	while True:
		x = heapq.heappop(q)
		h.remove(x)
		yield x
		for y in s:
			z = x * y
			if y != 1 and z not in h:
				heapq.heappush(q, z)
				h.add(z)


import heapq

def closure_gen(*s):
	s = set(sorted(s))
	buf = list(s)
	heapq.heapify(buf)
	while True:
		if len(buf) == 0:
			raise StopIteration
		val = heapq.heappop(buf)
		while len(buf) > 0 and buf[0] == val:
			heapq.heappop(buf)
		for v in s:
			if v <= 1:
				continue
			heapq.heappush(buf, val * v)
		yield val


from heapq import heapify, heappop, heappush

def closure_gen(*s):
	heap = [*s]
	heapify(heap)
	numbers = {*s}
	while heap:
		n = heappop(heap)
		yield n
		to_add = {n * i for i in s} - numbers
		numbers |= to_add
		for n in to_add:
			heappush(heap, n)


def closure_gen(*s):
	s = [*s]
	if 1 in s:
		s.remove(1)
		yield 1
	queue = [(n, n, 0) for n in s]
	numbers = [1]
	while queue:
		(prod, *_) = min(queue)
		yield prod
		numbers.append(prod)
		for (i, (p, n, d)) in enumerate(queue):
			if p <= prod:
				d += p == prod
				queue[i] = (numbers[d] * n, n, d)


def closure_gen(*seq):
	if not seq:
		return
	if seq == (1,):
		yield 1
		return
	if 1 in seq:
		yield 1
	seq = [i for i in seq if i != 1]
	(d, ind, li) = ({i: [i] for i in seq}, {i: 0 for i in seq}, [])
	while True:
		min_ = min((d[i][0] for i in d if d[i]))
		li.append(min_)
		yield min_
		for i in d:
			if d[i][0] == min_:
				d[i].pop(0)
			if not d[i]:
				d[i].append(li[ind[i]] * i)
				ind[i] += 1