-2

Write function count_Kprimes with given parameters k, start, nd, that returns a list of the k-primes between start (inclusive) and end (inclusive).

Here is my attempt:

def count_Kprimes(k, start, nd):
  ls = []
  for x in range(start, nd + 1):
    y = x
    l = []
    for i in range(2, x + 1):
      while y % i == 0:
        l.append(i)
        y /= i
    if len(l) == k:
      ls.append(x)
  return ls

However, my code takes too much time to process and I want to simply my code. How can it be done? Thank you so much!

This task is taken from Codewar

1 Answers1

0

Well, I had fun solving this anyway. Here is a solution based on array-logic

def count_Kprimes(k, start, nd):    
    x = np.arange(start, nd + 1, dtype=np.float)

    # divs will contain all divisors (plus one extra column)
    divs = np.ones((x.size, k + 1))

    # we have to loop only nd / 2^(k-1) to get all divisors
    for i in range(2, int(nd / 2 ** (k - 1)) + 1):

        # but each possible divisor "i" may occur up to k times
        # we loop until k+1 to catch also number that exceed our target,
        # so we can discard them later
        for j in range(1, k + 2):            

            # check for each row (dimension 0) if i is a divisor            
            # then set the first zero-value in dimension 1 to be this divisor                    
            d = np.prod(divs, axis=1)            
            divs[[[np.rint(x/d/i)==x/d/i][0],np.argmin(divs[np.rint(x/d/i)==x/d/i], axis=1)]] = i            

    # The correct result we're looking for is each row that has exactly
    # k values != 1 (which equals to exactly one "1" per row)
    indices = np.apply_along_axis(lambda x: x[x==1].size == 1, 1, divs)

    for val, d in zip(x[indices], divs[indices]):
        print "{} = {}".format(int(val), " * ".join([str(int(_)) for _ in d[:-1]]))

count_Kprimes(3, 1, 100)

returns

8 = 2 * 2 * 2
12 = 2 * 2 * 3
18 = 2 * 3 * 3
20 = 2 * 2 * 5
27 = 3 * 3 * 3
28 = 2 * 2 * 7
30 = 2 * 3 * 5
42 = 2 * 3 * 7
44 = 2 * 2 * 11
45 = 3 * 3 * 5
50 = 2 * 5 * 5
52 = 2 * 2 * 13
63 = 3 * 3 * 7
66 = 2 * 3 * 11
68 = 2 * 2 * 17
70 = 2 * 5 * 7
75 = 3 * 5 * 5
76 = 2 * 2 * 19
78 = 2 * 3 * 13
92 = 2 * 2 * 23
98 = 2 * 7 * 7
99 = 3 * 3 * 11
ascripter
  • 5,665
  • 12
  • 45
  • 68