Exploring Python Exercise - python

I am learning Python from the book Exploring Python by Timothy Budd. One of the exercises from this chapter is this:
15. The function randint from the random module can be used to produce random numbers. A call on random.randint(1, 6), for example, will produce the values 1 to 6 with equal probability. Write a program that loops 1000 times. On each iteration it makes two calls on randint to simulate rolling a pair of dice. Compute the sum of the two dice, and record the number of times each value appears. Afterthe loop, print the array of sums. You can initialize the array using the idiom shown earlier in this chapter:
times = [0] * 12 # make an array of 12 elements, initially zero
I am able to print the sum in the array, but I have not understood the concept of recording the number of times each value appears. Also, what purpose would times = [0] serve? Here is my code for printing the sum:
#############################################
# Program to print the sum of dice rolls #
#############################################
from random import randint
import sys
times = [0] * 12
summation = []
def diceroll():
print "This program will print the"
print "sum of numbers, which appears"
print "after each time the dice is rolled."
print "The program will be called 1000 times"
for i in range(1,1000):
num1 = randint(1,6)
num2 = randint(1,6)
sum = num1 + num2
summation.append(sum)
#times[i] = [i] * 12
print summation
#print times
diceroll()

times[0] * 12 initiates a list of 12 elements with value 0. What you want to do next is
times[s] += 1 #adds 1 to the number of times s occurs
This is similar to using a dict to encode a value, but its simpler.
times = [0] initializes a list called times of length 1 and value 0. The idiom times = [0] * 12 means times is a list of 12 zeroes.
If you want to be able to use this without keyerror when num1==num2==6, you need to do times = [0]*13 because python is a 0 indexed system.
Sidenote: Don't use sum as a variable name because it is a builtin function (predefined) and you don't want to override it. Use times[sum([num1,num2])] += 1 or times[num1+num2] instead.

To count number of occurrences:
times = [0]*13
for _ in range(1000):
sum_ = randint(1, 6) + randint(1, 6)
times[sum_] += 1
print(times[2:])
Possible values of sum_ are 2...12 including. Possible times indexes are 0...12 including.
times[i] corresponds to a number of occurrences of sum_ == i among 1000 tries.
Note: times[0] and times[1] are always zero because sum_ > 1
[x]*3 produces [x, x, x] It is a nicer version of:
L = []
L.append(x)
L.append(x)
L.append(x)
Additional comments about your code:
print something is an error on Python 3
for i range(1, 1000) is wrong. It produces i from 1 to 999 including (999 iterations instead of 1000 as required). range doesn't include upper limit as it customery for intervals in programming.

Related

I tried to solve this about factorials but it's not giving the right answer

this is the question:
Write a python code to find all the integers less than 50,000 that equal to
the sum of factorials of their digits. As an example: the number 7666 6=
7! + 6! + 6! + 6! but 145=1!+4!+5!
note: im not allowed to use any specific factorial function.
my solution:
import math
from numpy import *
for i in range(5):
for j in range(10):
for k in range(10):
for l in range(10):
for m in range(10):
x=1*m+10*l+100*k+1000*j+10000*i
def fact(m):
fact=1
for i in range(1,m+1):
fact=fact*i
return fact
y=fact(i)+fact(j)+fact(k)+fact(l)+fact(m)
if x==y :
print(x)
Hint 1
The reason this does not give you a correct answer is because there will be times where your code considers 0 to be a digit.
For example
fact(0)+fact(0)+fact(1)+fact(4)+fact(5) gives 147
because fact(0) is 1.
Hint 2
While your manner of iterating is interesting and somewhat correct, it is the source of your bug.
Try iterating normally from 1 to 50000 then figure out the sum of the digits a different way.
for i in range(50000):
# ...
Solution
Since this is StackOverflow, I offer a solution straightaway.
Use a function like this to find the sum of digits of a number:
def fact(m):
fact=1
for i in range(1,m+1):
fact=fact*i
return fact
def sumOfFactOfDigits(x):
# This function only works on integers
assert type(x) == int
total = 0
# Repeat until x is 0
while x:
# Add last digit to total
total += fact(x%10)
# Remove last digit (always ends at 0, ie 123 -> 12 -> 1 -> 0)
x //= 10
return total
for i in range(50000):
if i == sumOfFactOfDigits(i):
print(i)
Note
You should move your definition of fact outside of the loop.

How to make my Python code more time efficient?

The program I tried to execute has following problem statement:
The program must accept N integers containing integers from 1 to N
with duplicates in any order. The program must print the missing
integers from 1 to N among the given integers in ascending order as
the output.
example :
Input: 5
2 5 5 1 1
Output: 3 4
Explanation: The integers 3 and 4 are missing in the 5 integers 2 5 5
1 1. Hence 3 and 4 are printed as the output
My code :
def modusoperandi(n, t):
if str(n) not in t:
yield n
n = int(input())
t = tuple(sr for sr in input().split())
for i in range(1,n+1):
for j in modusoperandi(i,t):
print(j,end=' ')
My code, however, failed to pass all the test cases since it is takes considerable amount of time to execute for test cases with huge input[takes more than 500 ms which is the time limit].
I tried to compute execution time using timeit method. It is peculiar that when number of elements in tuple increase the execution time also increase for a given N. I prefered tuple over list since it is supposed to be more efficient.
You'll want to convert the existing numbers into integers, then put them in a set; sets are very efficient for figuring out whether or not a given value is a member.
n = int(input())
extant = set(int(n) for n in input().split())
for i in range(1, n + 1):
if i not in extant:
print(i, end=" ")
The key is indeed to use a set for checking the presence of expected numbers in the input string. You don't need to convert the input to integers though. You can do this the other way around by generating sequential numbers as strings.
nums = input().split()
numSet = set(nums)
missing = " ".join(str(n) for n in range(1,len(nums)+1) if str(n) not in numSet)
print(missing) # 3 4
For this particular problem, there is a slightly faster alternative to using a set because you can afford to create an array of flags with a known (and reasonable) size:
numbers = input().split()
present = [False]*len(numbers)
for n in numbers: present[int(n)-1] = True
missing = " ".join(str(n+1) for n,seen in enumerate(present) if not seen)
n = '5'
i = '2 5 5 1 1'
def compute(n, i):
s1 = set(range(1, n+1))
yield from sorted(s1.difference(i))
for val in compute(int(n), map(int, i.split()) ):
print(val, end=' ')
Prints:
3 4
You should think of the complexity of your solution (which is quite bad):
def modusoperandi(n, t):
# Since 't' is a tuple, the complexity of 'not in t' is O(len(t))
# This makes the overall complexity of this function O(len(t))
if str(n) not in t:
yield n
n = int(input())
t = tuple(sr for sr in input().split()) # O(len(t))
for i in range(1,n+1): # O(n) iterations
# 0 or 1 iteration, but the call to 'modusoperandi' is O(len(t))
for j in modusoperandi(i,t):
print(j,end=' ')
Overall complexity O(n * len(t)). This is not a very nice complexity. You'd like to have a complexity which is linear in the input. There are two ways:
Use a hash table to mark all visited integers, and set is such a hash-table. Unfortunately hash-tables have some shortcomings.
Since there are n entries and the numbers are in the range 1..n, then it is very efficient to use a characteristic vector values_encountered, in which values_encountered[i] is True if and only if i value was encountered. For big input, of this kind, this solution is likely to run faster than a set, and to consume less memory.
.
import numpy as np
n = int(input())
values_encountered = np.zeros(n+1, dtype=bool) # O(n)
values_encountered[[int(i) for i in input().split()]] = True # O(n)
# Or:
# values_encountered[list(map(int, input().split()))] = True
values_missing= (values_encountered == False) # O(n)
values_missing[0] = False
print(*list(*values_missing.nonzero())) # O(n)

Searching for the 'p' value in a coin toss simulation

Newbie to coding, attempting to find the 'p' value in a coin toss simulation.
Currently getting the attribute error:
'int' object has no attribute 'sum'.
How could it be? please Help.'''
import numpy as np
import random
attempts = 0
t = 0
for I in range (10000):
attempts = random.randint(2, 30)
if (attempts.sum >= 22 ):
t += 1
p = t / 10000
print(p)
If you are just trying to toss a coin 10,000 times and see how many turn up heads (or tails, if you prefer) then this is a simple way to do it. The random.random function returns a number such that 0 <= x < 1, so 50% of the time it should be less than .5.
import random
tosses = 100000
t = 0
for i in range(tosses):
if random.random() < .5:
t += 1
p = t / tosses
print(p)
attempts is the most recent random integer you generated. An int has no attribute (data field) sum. Since you haven't adequately described what you think your code does, we can't fix the problem.
Python's sum function adds up a sequence of items; see the documentation for examples.
You try to count something with variable m, but you give it no initial value.
You set t to 0, and later divide it by your loop limit, but you've never changed the value; this will be 0.0.
Update after OP comments
I think I understand now: you want to estimate the probability of getting at least 22 heads (or whatever side you choose) in a set of 30 tosses of a fair coin. I'll do my best to utilize your original code.
First of all, you have to toss a fair coin; the function call you made generates a random integer in the range [2, 30]. Instead, you need to do a call such as the below in groups of 30:
flip = random.randint(0,1)
This gives you a 0 or 1. Let's assume that we want to count 1 results: this allows us to simply add the series:
count = sum(random.randint(0,1) for _ in range(30))
This will loop 30 times, put the results in a list, and add them up; there's your count of desired flips. Now, do 10,000 of those 30-flip groups, checking each for 22 results:
import random
t = 0
for i in range (10000):
count = sum(random.randint(0,1) for _ in range(30))
if (count >= 22):
t += 1
p = t / 10000
print(p)
Now, if you want to tighten this even more, use the fact that a successful comparison (i.e. True) will evaluate to 1; False will be 0: make all 10,000 trials in an outer comprehension (in-line for):
t = sum(
sum(random.randint(0,1) for flip in range(30)) > 22
for trial in range(10000) )
print(t / 10000)
flip and trial are dummy loop variables; you can use whatever two you like.
Finally, it's usually better style to make named variables for your algorithms parameters, such as
threshhold = 22
trial_limit = 10000
flip_limit = 30
and use those names in your code.

Number of multiples less than the max number

For the following problem on SingPath:
Given an input of a list of numbers and a high number,
return the number of multiples of each of
those numbers that are less than the maximum number.
For this case the list will contain a maximum of 3 numbers
that are all relatively prime to each
other.
Here is my code:
def countMultiples(l, max_num):
counting_list = []
for i in l:
for j in range(1, max_num):
if (i * j < max_num) and (i * j) not in counting_list:
counting_list.append(i * j)
return len(counting_list)
Although my algorithm works okay, it gets stuck when the maximum number is way too big
>>> countMultiples([3],30)
9 #WORKS GOOD
>>> countMultiples([3,5],100)
46 #WORKS GOOD
>>> countMultiples([13,25],100250)
Line 5: TimeLimitError: Program exceeded run time limit.
How to optimize this code?
3 and 5 have some same multiples, like 15.
You should remove those multiples, and you will get the right answer
Also you should check the inclusion exclusion principle https://en.wikipedia.org/wiki/Inclusion-exclusion_principle#Counting_integers
EDIT:
The problem can be solved in constant time. As previously linked, the solution is in the inclusion - exclusion principle.
Let say you want to get the number of multiples of 3 less than 100, you can do this by dividing floor(100/3), the same applies for 5, floor(100/5).
Now to get the multiplies of 3 and 5 that are less than 100, you would have to add them, and subtract the ones that are multiples of both. In this case, subtracting multiplies of 15.
So the answer for multiples of 3 and 5, that are less than 100 is floor(100/3) + floor(100/5) - floor(100/15).
If you have more than 2 numbers, it gets a bit more complicated, but the same approach applies, for more check https://en.wikipedia.org/wiki/Inclusion-exclusion_principle#Counting_integers
EDIT2:
Also the loop variant can be speed up.
Your current algorithm appends multiple in a list, which is very slow.
You should switch the inner and outer for loop. By doing that you would check if any of the divisors divide the number, and you get the the divisor.
So just adding a boolean variable which tells you if any of your divisors divide the number, and counting the times the variable is true.
So it would like this:
def countMultiples(l, max_num):
nums = 0
for j in range(1, max_num):
isMultiple = False
for i in l:
if (j % i == 0):
isMultiple = True
if (isMultiple == True):
nums += 1
return nums
print countMultiples([13,25],100250)
If the length of the list is all you need, you'd be better off with a tally instead of creating another list.
def countMultiples(l, max_num):
count = 0
counting_list = []
for i in l:
for j in range(1, max_num):
if (i * j < max_num) and (i * j) not in counting_list:
count += 1
return count

Writing a Python program that finds the square of a number without using multiplication or exponents?

thank you for reading and hopefully responding to my question. I'm stuck trying to write this Python program that finds a number's square without using multiplication or exponents. Instead, I have to get the summation of the first odd n numbers starting from 1. This is what I have so far:
def square():
print("This program calculates the square of a given number")
print("WITHOUT using multiplication! ")
odd = 1
n = eval(input("Enter a number: "))
for odd in range(0, n + 1, 2):
odd = odd + 2
final_square = n + odd
print(n, "squared is", final_square, ".")
EDIT: Hi guys, I can't do 4 + 4 + 4 + 4. I have to do 1 + 3 + 5 + 7, and I'm not sure how. It gives me 4 squared is 11 or something.
Just some tips:
Try not to use eval(), it will evaluate any input given and so it can do something you don't want to do. Instead, use int().
Remember that, say 4*4, is just 4 + 4 + 4 + 4. You're on the right track with a for-loop, but now make the loop iterate n times adding n to itself.
new = 0
for _ in range(n):
new += n
Note that this won't work with negative numbers. If you're going to be dealing with those, perhaps get the absolute value of n at the beginning:
def square(n):
n = abs(n)
....
Since you have been told you have to get the answer by producing the first n odd numbers, then you need to think about how to do that - certainly your loop isn't doing that :
several issues :
you do odd =1, and then use odd in your for loop, the two can't co-exist, so the initial value of odd = 1 is overwritten.
Your loop doesn't produce the first n odd numbers that I can see.
My suggest would be to rework your loop : the first 'n' odd numbers are in the form :
1, 3, 5, ... n*2-1
(Counting from 1 not from zero)
so a loop like this :
final = 0
for c in range(1, n+1): #start counting from 1 to do 1 to n+1
odd = c*2 -1 #Use the series above to generate each odd number.
final += odd
should work
a much more 'pythonic' way to do this is :
final = sum(c*2-1 for c in range(1,n))
This uses a generator to create all of the odd numbers (the equivalent of the loop), and sum the values as they get created.
Go back to the original definition of multiplication.
Just add the number n to itself n times. What's so hard? It's inefficient has hell, but it'll work.
I'm sure there's a more Pythonic way:
def square(n):
sum = 0
for i in range(0,n):
sum = sum + n
return sum

Categories