I have a simple example,
Create a program that asks the user for a number and then prints out a list of all the divisors of that number.
And i am solving it like this:
n = 4
list_range = list(range(1,n+1))
divisor_list = []
divisor_list.append([i for i in list_range if n%i==0])
print divisor_list
#output:
#[[1, 2, 4]]
I want the output to be [1, 2, 4]
I can achieve this by:
n = 4
list_range = list(range(1,n+1))
divisor_list = []
for i in list_range:
if n % i == 0:
divisor_list.append(i)
print divisor_list
#output:
#[1, 2, 4]
But is there a better way of achieving this ?
It makes no sense to loop through all range of numbers, it's a waste! Just try to prove there are no more divisors after n/2, here's another benchmarked version comparing an alternative method f2:
import math
import timeit
def f1(num):
return [i for i in range(1, num + 1) if num % i == 0]
def f2(num):
square_root = int(math.sqrt(num)) + 1
output = []
for i in range(1, square_root):
if (num % i == 0 and i * i != num):
output.append(i)
output.append(num / i)
if (num % i == 0 and i * i == num):
output.append(i)
return output
def bench(f, N):
for n in range(1, N):
f(N)
N = 10000
print timeit.timeit('bench(f1, N)', setup='from __main__ import bench, f1, N', number=1)
print timeit.timeit('bench(f2, N)', setup='from __main__ import bench, f2, N', number=1)
Results on my cpu are:
4.39642974016
0.124005777533
f2 won't give a sorted list, but that's irrelevant, you didn't mention that in your question
Use extend:
divisor_list.extend([i for i in list_range if n%i==0])
You can use assign the result of the list comprehension to the variable.
You don't need to initialize divisor_list as an empty sequence at all. The comprehension you're appending is the actual answer you're looking for.
divisor_list = [i for i in list_range if n%i==0]
You don't need append, just use:
divisor_list = [i for i in list_range if n% i == 0]
This way you just assign the result of list comprehension, giving you one clean list. No need to append a list, that will nest a list in a list, and no need to initialize as an empty list. That's redundant because you add to the list just the next line. Just assign to list comprehension. As #joel goldstick mentioned, you can just loop over half of list_range because nothing will be a division if it's more than 1/2 the number:
list_range = list(range(1, (n / 2) + 1))
Related
I have a code for squaring each number in a list in Python, but I have issues with it. My code doesn't give me the right answer. If I have [2,3,4,5,6,7] the answer should be [4, 9, 16, 25, 36, 49], but I get [49]. Here’s my code:
numList = [2,3,4,5,6,7]
def square (N):
sq = N * N
return (sq)
def cmput_square(numList):
i = 0
L = []
while i < len (numList):
L = [square(numList[i])]
i = i + 1
return (L)
n = cmput_square (numList)
print ("The squares of your numbers are:", n)
Your problem is that you are replacing L every time, instead of appending to L. The following should work:
numList = [2,3,4,5,6,7]
def square (N):
sq = N * N
return (sq)
def cmput_square(numList):
i = 0
L = []
while i < len (numList):
L.append(square(numList[i]))
i = i + 1
return (L)
n = cmput_square (numList)
print ("The squares of your numbers are:", n)
prints:
The squares of your numbers are: [4, 9, 16, 25, 36, 49]
If you would like to reduce the number of lines of code required, you could change it to a single function with a list iteration:
def cmput_square(numList):
return([i*i for i in numList])
[EDIT] Seeing as you can't use .append or a list comprehension as per your comment, here is another way, again as a single function. I'd argue it's less elegant, but it gets you what you need:
def cmput_square(numList):
L = [0] * len(numList)
for i in range(len(numList)):
L[i] = numList[i]*numList[i]
return(L)
[EDIT #2] and without using for or range, you can do it this way:
def cmput_square(numList):
L = [0] * len(numList)
i = 0
while i < len(numList):
L[i] = numList[i]*numList[i]
i = i+1
return(L)
the current way you create your list overwrites L with a one item list each time it is called. You can either use L.append(square(numList[i])) instead of L = [square(numList[i])] of you can create the whole list in one line by a list comprehension:
def cmput_square(numList):
return [square(i) for i in numlist]
Happy birthday - just use .append()
numList = [2,3,4,5,6,7]
def square (N):
sq = N * N
return (sq)
def cmput_square(numList):
i = 0
L = []
while i < len (numList):
L.append(square(numList[i]))
i += 1
return (L)
n = cmput_square (numList)
print ("The squares of your numbers are:", n)
replace
L = [square(numList[i])]
with
L += [square(numList[i])]
in case you wanted a shorter version:
numList = [2,3,4,5,6,7]
L = [numList[i]**2 for i in range(len(numList))]
print ("The squares of your numbers are:", L)
def problem(n):
myList = []
for i in range(2, n):
if n % i == 0:
myList.append(i)
return myList
with this code I was wondering how you would get the factors for example 12 to print out as[[6,2],[3,4]] something like this dosnt have to be in same order thanks.
This should work for you:
import math
def problem(n):
myList = []
for i in range(2, int(math.sqrt(n) + 1)):
if n % i == 0:
myList.append([i, int(n/i)])
return myList
To get the factor pair, this divides n by i, if i is a factor, which will by i's pair.
example:
print(problem(12)) #output: [[2, 6], [3, 4]]
Another way. Loop using range and check if is_integer
num = 12
set([tuple(sorted(j)) for j in [[i, int(num/i)] for i in range(2,num) if (num/i).is_integer()]]
)
#Output:
#{(2, 6), (3, 4)}
You are almost correct . Using range you are not taking the number. Just add n+1 instead of n. That should work. Also you are not stroing the divident in the list. I added that too.
def problem(n):
myList = []
for i in range(2, n+1):
if n % i == 0 and [int(n/i),i] not in myList:
myList.append([i,int(n/i)])
return myList
In order to do the division only once:
for i in range(2, int(math.sqrt(n) + 1)):
d, m = divmod(n, i)
if m == 0:
myList.append([i, d])
You will not get duplicates with upper limit sqrt(n)
I want to find a sequence of n consecutive integers within a sorted list and return that sequence. This is the best I can figure out (for n = 4), and it doesn't allow the user to specify an n.
my_list = [2,3,4,5,7,9]
for i in range(len(my_list)):
if my_list[i+1] == my_list[i]+1 and my_list[i+2] == my_list[i]+2 and my_list[i+3] == my_list[i]+3:
my_sequence = list(range(my_list[i],my_list[i]+4))
my_sequence = [2,3,4,5]
I just realized this code doesn't work and returns an "index out of range" error, so I'll have to mess with the range of the for loop.
Here's a straight-forward solution. It's not as efficient as it might be, but it will be fine unless you have very long lists:
myarray = [2,5,1,7,3,8,1,2,3,4,5,7,4,9,1,2,3,5]
for idx, a in enumerate(myarray):
if myarray[idx:idx+4] == [a,a+1,a+2,a+3]:
print([a, a+1,a+2,a+3])
break
Create a nested master result list, then go through my_sorted_list and add each item to either the last list in the master (if discontinuous) or to a new list in the master (if continuous):
>>> my_sorted_list = [0,2,5,7,8,9]
>>> my_sequences = []
>>> for idx,item in enumerate(my_sorted_list):
... if not idx or item-1 != my_sequences[-1][-1]:
... my_sequences.append([item])
... else:
... my_sequences[-1].append(item)
...
>>> max(my_sequences, key=len)
[7, 8, 9]
A short and concise way is to fill an array with numbers every time you find the next integer is the current integer plus 1 (until you already have N consecutive numbers in array), and for anything else, we can empty the array:
arr = [4,3,1,2,3,4,5,7,5,3,2,4]
N = 4
newarr = []
for i in range(len(arr)-1):
if(arr[i]+1 == arr[i+1]):
newarr += [arr[i]]
if(len(newarr) == N):
break
else:
newarr = []
When the code is run, newarr will be:
[1, 2, 3, 4]
#size = length of sequence
#span = the span of neighbour integers
#the time complexity is O(n)
def extractSeq(lst,size,span=1):
lst_size = len(lst)
if lst_size < size:
return []
for i in range(lst_size - size + 1):
for j in range(size - 1):
if lst[i + j] + span == lst[i + j + 1]:
continue
else:
i += j
break
else:
return lst[i:i+size]
return []
mylist = [2,3,4,5,7,9]
for j in range(len(mylist)):
m=mylist[j]
idx=j
c=j
for i in range(j,len(mylist)):
if mylist[i]<m:
m=mylist[i]
idx=c
c+=1
tmp=mylist[j]
mylist[j]=m
mylist[idx]=tmp
print(mylist)
I am looking into a problem: given an arbitrary list, in this case it is [9,15,1,4,2,3,6], find any two numbers that would sum to a given result (in this case 10). What would be the most efficient way to do this? My solution is n2 in terms of big O notation and even though I have filtered and sorted the numbers I am sure there is a way to do this more efficiently. Thanks in advance
myList = [9,15,1,4,2,3,6]
myList.sort()
result = 10
myList = filter(lambda x:x < result,myList)
total = 0
for i in myList:
total = total + 1
for j in myList[total:]:
if i + j == result:
print i,j
break
O(n log n) solution
Sort your list. For each number x, binary search for S - x in the list.
O(n) solution
For each number x, see if you have S - x in a hash table. Add x to the hash table.
Note that, if your numbers are really small, the hash table can be a simple array where h[i] = true if i exists in the hash table and false otherwise.
Use a dictionary for this and for each item in list look for total_required - item in the dictionary. I have used collections.Counter here because a set can fail if total_required - item is equal to the current item from the list. Overall complexity is O(N):
>>> from collections import Counter
>>> def find_nums(total, seq):
c = Counter(seq)
for x in seq:
rem = total - x
if rem in c:
if rem == x and c[rem] > 1:
return x, rem
elif rem != x:
return x, rem
...
>>> find_nums(2, [1, 1])
(1, 1)
>>> find_nums(2, [1])
>>> find_nums(24, [9,15,1,4,2,3,6])
(9, 15)
>>> find_nums(9, [9,15,1,4,2,3,6])
(3, 6)
I think, this solution would work....
list = [9,15,1,4,2,3,6]
result = 10
list.sort()
list = filter(lambda x:x < result,list)
myMap = {}
for i in list:
if i in myMap:
print myMap[i], i
break
myMap[result - i] = i
So pretty much first set of code creating a list of primes from 2 - 10000000. i am trying to find the prime factorization for 25000001. so i want it to divide 25000001 by each number in the list and return that number to a list largest to smallest.
n = 10000000
primes = list()
multiples = set()
for i in range(2, n+1):
if i not in multiples:
primes.append(i)
multiples.update(range(i*i, n+1, i))
def primeFactors(x, factors):
factorList = []
if (x % factors) == 0:
factorList.append(factors)
print(factorList)
primeFactors(25000001, primes)
You can use a list comprehension:
factorList = [e for e in factors if x % e == 0]
The part
e for e in factors
will "iterate" over the elements of factors, and the condition if x % e == 0 is used to filter the elements.
If you want to check each number in factors against x, you need to iterate over
for n in factors: # iterate over the list
if x % n == 0: # check "n" each number in the list
factorList.append(n) # append n if the if statement is True
[1,2,3,4...] % 3 is basically what you are currently doing, not checking each element.
You can achieve the same with a list comprehension:
factorList = [n for n in factors if x % n == 0]
Both the for loop and the list comprehension are equivalent.
To print it out in the format you want:
print "{} = {}".format(x," * ".join(map(str,factorList)))
If you just plan on printing the numbers, you can make them strings in the loop or list comprehension:
[str(x) for x in factors if n % x == 0]
print "{} = {}".format(x," * ".join(factorList))
To use join the elements need to be strings, so we would have to use the str(x) or use map to convert each int to string.
What you're trying to do here is actually doable, just not with lists. If you use a numpy array, you can throw it into arithmetic expressions, and it automatically broadcasts them over the whole array:
>>> import numpy as np
>>> primes = np.array([2, 3, 5, 7, 11])
>>> 18 % primes
array([0, 0, 3, 4, 7])
>>> 18 % primes == 0
array([ True, True, False, False, False], dtype=bool)
>>> primes[18 % primes == 0]
array([2, 3])
That's exactly what you were trying to do, almost exactly the way you were trying to do it—and it works exact as you'd expect it to.
This is obviously more concise, and it's almost always much more efficient; more importantly than either, it's often more readable.
What if you want to find repeated factors? Well, you can square the whole array, then cube it, and so on:
>>> primes[18 % (primes**2) == 0]
array([3])
>>> primes[18 % (primes**3) == 0]
array([])
Or, more efficiently, you can restrict the work to just the filtered-down array, and get the same results with a lot less work:
>>> factors = primes[18 % primes == 0]
>>> factors2 = factors[18 % (factors**2) == 0]
>>> factors2
array([3])