I would like to generate 4 digits random number in Python but exclude all the numbers that have a "0" inside. For example, 9230, 2012 will not be accepted since there is a 0.
My code is:
def my_custom_random():
exclude=[0]
randInt = randint(1000, 9999)
return my_custom_random() if randInt in exclude else randInt
def Q3a():
RandomNumber = my_custom_random())
print(RandomNumber)
Q3a()
But this code is not working. Anyone can help me ? Thanks.
Congratulations for not picking the easy but expensive solution, consisting in calling 4 times the random number generator for a number between 1 and 9 inclusive.
we can basically keep your recursive scheme, but delegate the hard work to another function, isBadNumber(). Like this:
def my_custom_random():
randInt = random.randint(1111, 9999)
return my_custom_random() if isBadNumber(randInt) else randInt
To decide whether some number is acceptable or not, we need some auxiliary function that returns the list of digits:
# get at least k digits for a number in some arbitrary base:
def xdigits(k, base, n):
if (n < base):
res = (k-1)*[0] + [n]
else:
res = xdigits(k-1, base, n // base) + [n % base]
return res
Trying:
>>>
>>> q.xdigits(4,10,56)
[0, 0, 5, 6]
>>>
>>> q.xdigits(4,10,123456)
[1, 2, 3, 4, 5, 6]
>>>
>>> q.xdigits(4,10,7702)
[7, 7, 0, 2]
>>>
Thus we can write our isBadNumber() function like this:
def isBadNumber(n):
if ((n < 1111) or (n > 9999)):
return True
ds = xdigits(4, 10, n)
if (min(ds) < 1):
return True # having a zero
return False # passed all tests OK.
Addendum: a method without rejection:
Rejection costs CPU time, so it is always nice if we can do without it. For each of the 4 digits, there are 9 possibilities, 1 to 9 inclusive. Hence the overall number of solutions is 94, hence 6561. As programmers use to do, we can decide to number them from 0 to 6560 inclusive.
So we can pick one of them like this:
>>>
>>> import random
>>> import functools as fn
>>>
>>> random.randint(0,6560)
3952
>>>
If we express this number in base 9 (not 10), we get 4 digits between 0 and 8 inclusive. This is exactly what we need, provided we add 1 to every digit.
>>>
>>> q.xdigits(4,9,3952)
[5, 3, 7, 1]
>>>
We add 1 to every digit, giving [6, 4, 8, 2]. Hence, the 3952-th solution is number 6482.
Going from 3952 thru [5,3,7,1] to 6482 can be done using some simple Python data massaging:
>>>
>>> ds1 = list(map(lambda n: n+1, [5, 3, 7, 1]))
>>> ds1
[6, 4, 8, 2]
>>>
>>> fn.reduce(lambda acc, d: acc*10 + d, ds1)
6482
>>>
So overall the rejection-free code would be like this:
def my_custom_random():
randomRank = random.randint(0, 9**4 - 1)
ds0 = xdigits(4, 9, randomRank)
ds1 = list(map(lambda n: n+1, ds0))
num = functools.reduce(lambda acc, d: acc*10 + d, ds1)
return num
Basically, if you don't want zeros then don't pick zeros. Pick from [1..9] only, so you never pick a zero.
Here is some pseudocode; my Python is not good.
function noZeros()
digits <- [1,2,3,4,5,6,7,8,9] // Zero omitted.
result <- 0
repeat 4 times
result <- 10 * result;
thisDigit <- pick a random entry from digits array
result <- result + thisDigit
end repeat
return result
end function noZeros
I am sure you can write a better version in Python.
I hope it will help you
import random
def my_custom_random():
exclude = 0
digits = [0,1,2,3,4,5,6,7,8,9]
randNumber = random.sample(digits,4) #List of integers Ex. [2,9,1,6]
while exclude in randNumber:
randNumber = random.sample(digits,4)
return map(str,randNumber) #map(str, x) -> transform [2,9,1,6] to ['2','9','1','6']
def Q3a():
randNumber = my_custom_random()
randNumber = "".join(randNumber) # ['2','9','1','6'] to '2916'
print(int(randNumber))
Q3a()
In digits you can omit the 0, so you can write less code. This way you will never have numbers with zero.
def my_custom_random():
digits = [1,2,3,4,5,6,7,8,9]
randNumber = random.sample(digits,4)
return map(str,randNumber)
Related
How would you go about this:
Write your own infinite precision "sum", "product", and "to the power of" functions, that represent numbers as lists of
digits between 0 and 9 with least significant digit first.
Thus: 0 is represented as the empty list [], and 10 is represented as [0,1].
You may assume that numbers are non-negative (no need for negative numbers, or for subtraction).
I have functions to convert to and from.
eg:
iint(5387) == [7, 8, 3, 5] and pint([7, 8, 3, 5]) == 5387
def iint(n):
# list of all digits in the int
digits = [int(x) for x in str(n)]
# reverse the list
digits.reverse()
return digits
def pint(I):
# new int c
c = 0
# iterates through list
for i in range(len(I)):
# add to c digit in the list multiplied by 10^of its position in the list. 1, 10, 100, 1000 ect.
c = c + I[i] * (10 ** i)
return c
# add two infinite integers
def iadd(I, J):
pass
First though would be just convert back to int do the calculation and then back again but that would "gut the question".
Not looking for a complete solution just some pointers on where to start for iadd()because I am completely stumped. I assume after you get iadd() the rest should be simple enough.
For writing your iadd function, one way is to use test-driven development; write your test inputs, and your expected outputs. assert that they're equal, then rewrite your function so it passes the testcase.
In the particular case of needing to add two lists of numbers together, "how would you do that by hand?" (as noted by a comment) is an excellent place to start. You might
starting from the least-significant digit
add individual digits together (including a carry from the previous digit, if any)
carry the "high" digit if the result is > 9
record the result of that addition
loop from step 2 until you exhaust the shorter number
if you have a carry digit "left over," handle that properly
if one of the input numbers has more digits than the other, properly handle the "left over" digits
Here's a code snippet that should help give some ideas:
for d in range(min(len(I),len(J))):
added = I[d] + J[d]
digit = added%10 + carry
carry = added//10
And some testcases to try:
assert iadd([1], [1]) == [2] # 1 + 1 == 2
assert iadd([0,1], [1]) == [1,1] # 10 + 1 == 11
assert iadd([9,1], [1]) == [0,2] # 19 + 1 == 20
assert iadd([9,9,9,9,9], [2]) == [1,0,0,0,0,1] # 99,999 + 2 == 100,001
assert iadd([4,0,2], [9,2,3,4,1]) == [3,3,5,4,1] # 201 + 14,329 == 14,533
Itertools's zip_longest should be very useful to implement the addition operation.
For example:
def iint(N): return [int(d) for d in reversed(str(N))]
def pint(N): return int("".join(map(str,reversed(N))))
from itertools import zip_longest
def iadd(A,B):
result = [0]
for a,b in zip_longest(A,B,fillvalue=0):
result[-1:] = reversed(divmod(a+b+result[-1],10))
while result and not result[-1]: result.pop(-1) # remove leading zeros
return result
a = iint(1234)
b = iint(8910)
print(iadd(a,b)) # [4, 4, 1, 0, 1] (10144)
For the multiplication, you should make sure to keep the intermediate results below 100
def iprod(A,B):
result = []
for iA,a in enumerate(A):
if not a: continue
result = iadd(result,[0]*iA+[a*d for d in B]) # a*d+9 <= 90
return result
print(iprod(a,b)) # [0, 4, 9, 4, 9, 9, 0, 1] 10994940
For the power operation, you'll want to break down the process into a reasonable number of multiplications. This can be achieved by decomposing the exponent into powers of 2 and multiplying the result by the compounded squares of the base (for 1 bits). But you'll need to make a division by 2 function to implement that.
This strategy is based on the fact that multiplying a base raised to various powers, adds these powers:
A^7 * A^6 = A^13
and that any number can be expressed as the sum of powers of two:
13 = 1 + 4 + 8,
so
A^13 = A^1 * A^4 * A^8.
This reduces the number of multiplications for A^B down to 2log(B) which is much less than multiplying A by itself B-1 times (although we'll be dealing with larger numbers).
def idiv2(N):
result = N.copy() or [0]
carry = 0
for i,d in enumerate(reversed(N),1):
result[-i],carry = divmod(result[-i]+carry*10,2)
return result if result[-1] else result[:-1]
def ipow(A,B):
result, a2n = [1], [] # a2n is compounded squares A, A^2, A^4, A^8, ...
while B:
a2n = iprod(a2n,a2n) if a2n else A
if B[0]%2 : result = iprod(result,a2n)
B = idiv2(B)
return result
print(ipow(iint(12),iint(13)))
# [2, 7, 0, 9, 7, 3, 5, 0, 2, 3, 9, 9, 6, 0, 1] 106993205379072
print(len(ipow(a,b))) # 27544 digits (takes a long time)
Further optimization could be achieved by creating a specialized square function and using it instead of iprod(a2n,a2n)
When I split certain numbers into "ones" and "tens" in python, like that (98) we code >>>
num = 98
ones = num % 10
tens = num // 10
print(ones) = 8
print(tens) = 9
So, if I have 3 digits number like 321 (based on the code have shown previously) the ones will be 1, tens = 32 . and I need python to execute 3 and 2 separately !!
First, you can use divmod:
tens, ones = divmod(98, 10)
tens
# 9
ones
# 8
Second, you could write a generic function to get all digits regardless of magnitude:
def digs(n):
while n:
n, dig = divmod(n, 10)
yield dig
ones, tens, hundreds, *_ = digs(321)
It will always produce all digits starting with ones:
[*digs(12345)]
# [5, 4, 3, 2, 1]
Of course, the simplest is just string conversion:
[*map(int, str(12345))]
# [1, 2, 3, 4, 5]
This is a generic Python code to split the digits (ones, tens, hundreds, and so on)
num = int(input())
count = 0
while (num != 0):
mod = num % 10
div = num // 10
count = count + 1
print ("The number in position", count, " is ", mod)
num = div
This code works by repeated division.
You can write a function doing the modulo operations, put those in a list, make the division by then and repeat until the end, reverse the list:
def split_number(number):
result = []
while number != 0:
result.append(number % 10)
number = number // 10
result.reverse()
return result
split_number(12345)
[1, 2, 3, 4, 5]
like this :
321 / 100
3.21
>>> int(3.21)
3
But you have already made a better thing for 10 why you don't make it for 100?
I'm having an issues creating a function that takes one number as its input and doubles that number three times using a loop.
For example taking the input 2 and returning 4,8,16
What I've tried so far is the following
def doubles(i):
for n in range(2:5):
doubled_num = i ** n
return doubled_num
i = 2
output_num = doubles(i)
print output_num
def f(n):
n_d = n*2
n_tri = n_d*2
fin_n = n_tri*2
return n_d,n_tri,fin_n
In [6]: f(2)
(4, 8, 16)
Using a loop like your own example:
def f(n):
result=[]
for i in range(3): # loop 3 times
n*=2 # n doubles each time through the loop
result.append(n) #add new value of n to result list
return result
In [10]: f(2)
[4, 8, 16]
Range starts at 0, going 0,1,2, it does not include the upper end.
Using n*=2 is the same as n = n * 2
Concise (but not very efficient):
def doubles(i, n=3):
return [i * 2**x for x in range(1, n+1)]
then
>>> doubles(2)
[4, 8, 16]
def doubles(num):
"""Return the result of multiplying an input number by 2."""
return num * 2
# Call doubles() to double the number 2 three times
my_num = 2
for i in range(0, 3):
my_num = doubles(my_num)
print(my_num)
I want to know how to add to digits together in a list. Say the number is 10. I need it to add 1 + 0 to the new list. If the item in the list is 11 it needs to add 2 to the list
def main():
#Define List
mylist = [4,5,5,2,7,2,0,4,1,2,3,4,5,6,7,8]
print(mylist)
newlist = []
for each in mylist:
if (each % 2 == 0):
newlist.append(each)
else:
newlist.append(each + each)
for each in newlist:
if each >= 10:
newlist.append(each + each)
print(newlist)
main()
To get the digit sum of a number, you should convert the number to a string, loop over the string, and add all chars together (after converting them to int again):
def get_digit_sum(num):
return sum(int(x) for x in str(num))
To do this for a list of numbers, you should use list comprehension:
>>my_nums = [11, 22, 56, 345]
>>digit_sums = [get_digit_sum(x) for x in my_nums]
>>print(digit_sums)
[2, 4, 11, 12]
This is also possible to do in one expression:
>>my_nums = [11, 22, 56, 345]
>>digit_sums = [sum(int(x) for x in str(num)) for num in my_nums]
As per abarnet's comment, you may want the number 345 to be converted to 3+4+5=12, and the convert 12 to 1+2=3. This can be done using recursion. By using a max_digits parameter, you can specify the maximum number of digits in the returned number.
def get_digit_sum(num, max_digits=1):
d = sum(int(x) for x in str(num))
if len(str(d)) > max_digits:
return get_digit_sum(d)
return d
or a bit shorter:
def get_digit_sum(num, max_digits=1):
d = sum(int(x) for x in str(num))
return get_digit_sum(d) if len(str(d)) > max_digits else d
Both of the above functions would then yield:
>>my_nums = [11, 22, 56, 345]
>>print [get_digit_sum(x) for x in my_nums]
[2, 4, 2, 3]
It looks like your code is trying to do a little bit more than what you describe - in particular, you double any odd numbers. Because you're doing two things to each number (possibly double, sum the digits), you don't want to put it in the list until both steps are done. Instead do something like this:
for each in mylist:
if each % 2 != 0:
each *= 2
if each >= 10:
each = # sum of digits
newlist.append(each)
There's a couple of ways you could sum the digits. You can use divmod to get the quotient and the remainder of the number divided by 10 - the remainder is the units column, the quotient is every column to the left of that:
if each >= 10:
q, r = divmod(each, 10)
each = q + r
the other way is to get the string representation, which lets you iterate over every digit, convert it back to a number and add them:
if each >= 10:
each = sum(int(d) for d in str(each))
this is possibly easier to understand It is, however, a fair bit slower - which might matter if you have a very large amount of input.
These two approaches do work differently if you end up with any three or more digit numbers in the list - for 110, the divmod version will do 11 + 0 = 11, while the string version will do 1 + 1 + 0 = 2.
Also note that neither is guaranteed to end up with a single-digit number in the end - for 99, both of these will give you 18. If you want that further reduced to 9, you can change the if to a loop:
while each >= 10:
each = sum(int(d) for d in str(each))
to do this for the divmod version, you could put it into a recursive function instead:
def digit_sum(number):
q, r = divmod(number, 10)
if q > 10:
q = digit_sum(q)
return q+r
Making the same change to the divmod version as the string version appears to give the same answer in every case I've tried, but I have no idea if this is guaranteed to be the case.
> [int(d) for d in str(123)]
[1, 2, 3]
Try this:
A function that sums the digits for a given number:
def sum_of_digits(num):
return sum([int(x) for x in str(num)])
And a list comprehension to apply it to the entire list:
newlist=[sum_of_digits(number) for number in mylist]
I believe I know what you are going for. If the value is even and less than 10 add it to the new list, if the value is odd then double it and if that is less than 10 add it to the new list. Now if the value is greater than 10 then take the sum of all the digits and add it to the list.
I am sure there is a better way to do this, but this is what I came up with.
list = [4,5,5,2,7,2,0,4,1,2,3,4,5,6,7,8]
newlist = []
for i in list:
if i % 2 == 0 and len(str(i)) > 1:
newlist.append(sum([int(x) for x in str(i)]))
elif i % 2 == 0:
newlist.append(i)
elif len(str(i*2)) > 1:
newlist.append(sum([int(x) for x in str(i*2)]))
else:
newlist.append(i*2)
print newlist
input: [4, 5, 5, 2, 7, 2, 0, 4, 1, 2, 3, 4, 5, 6, 7, 8]
outcome: [4, 1, 1, 2, 5, 2, 0, 4, 2, 2, 6, 4, 1, 6, 5, 8]
I am just wondering how do I make python generate random numbers other than a particular number? For instance, I want it to generate any number from 1 to 5 except 3, so the output would be 1, 2, 4, 5 and 3 will not be counted in the list. What can I do to achieve that?
An example would be like this:
There are five computerized players (Player 0 to 4) in a game.
Player 1 randomly selects one other player (except itself) and Player 2 to 4 will do the same thing.
So the output will be something like:
Player 1, who do you want to play with?
Player 1 chooses Player 2
Use random.choice on a list, but first remove that particular number from the list:
>>> import random
>>> n = 3
>>> end = 5
>>> r = list(range(1,n)) + list(range(n+1, end))
>>> r
[1, 2, 4]
>>> random.choice(r)
2
>>> random.choice(r)
4
Or define a function:
def func(n, end, start = 1):
return list(range(start, n)) + list(range(n+1, end))
...
>>> r = func(3, 5)
>>> r
[1, 2, 4]
>>> random.choice(r)
2
Update:
This returns all numbers other than a particular number from the list:
>>> r = range(5)
for player in r:
others = list(range(0, player)) + list(range(player+1, 5))
print player,'-->', others
...
0 --> [1, 2, 3, 4]
1 --> [0, 2, 3, 4]
2 --> [0, 1, 3, 4]
3 --> [0, 1, 2, 4]
4 --> [0, 1, 2, 3]
It sounds as if you want to produce a random set of numbers, then pick from those one-by-one. A random sequence without repetition, in other words.
Generate all those numbers, shuffle, then use .pop() to pick one at a time and remove it from the set of possibilities:
import random
numbers = range(5) # list(range(5)) in Python 3
random.shuffle(numbers)
a_random_number = numbers.pop()
another_random_number = numbers.pop()
list.pop() removes the last value from the list of randomly shuffled numbers.
It may be enough even to just shuffle and then loop over the list:
players = range(5)
random.shuffle(players)
for player in players:
# random ordering of players
You can bundle the random-number-sequence production up as an iterator in a function:
import random
def random_number_sequence(n):
numbers = range(n) # list(range(n)) in Python 3
random.shuffle(numbers)
return iter(numbers)
random_sequence = random_number_sequence(5)
a_random_number = next(numbers)
another_random_number = next(numbers)
You can call next() on the iterator and it'll produce another random number from the sequence, until the sequence is exhausted (at which point StopIteration is returned).
While other answers are correct. The use of intermediate lists is inefficient.
Alternate Solution:
Another way you could do this is by choosing randomly from a range of numbers that is n-1 in size. Then adding +1 to any results that are greater than or equal to >= the number you want to skip.
The following function random_choice_except implements the same API as np.random.choice, and so adjusting size allows efficient generation of multiple random values:
import numpy as np
def random_choice_except(a: int, excluding: int, size=None, replace=True):
# generate random values in the range [0, a-1)
choices = np.random.choice(a-1, size, replace=replace)
# shift values to avoid the excluded number
return choices + (choices >= excluding)
random_choice_except(3, 1)
# >>> 0 <or> 2
random_choice_except(3, 1, size=10)
# >>> eg. [0 2 0 0 0 2 2 0 0 2]
The behaviour of np.random.choice changes depending on if an integer, list or array is passed as an argument. To prevent unwanted behavior we may want to add the following assertion at the top of the function: assert isinstance(a, int)
In this case, random.choice will work fine, but there's also an obvious simple mathematical transform you could use. If players are numbered 0 through 5 inclusive, and you are player X, then:
number = random.randint(0, 4) # first, pick a number: 0, 1, 2, 3, or 4
if number >= X: # then, if it's me or higher...
number += 1 # move forward one player
Note that this works no matter which player number you are. If you are #5, this picks a number between 0 and 4, which is not you (because you are #5). If you are #0, this picks a number between 0 and 4, which is >= you (because you are #0) so you add 1 giving a number between 1 and 5. If you are #3, this picks a number between 0 and 4, and if it's 3 or 4 you bump it up one to 4 or 5 respectively.
Edit to add: this won't allow you to do "fair" alternation (where everyone gets a turn before someone gets to go again). If you want that, generating a list, using random.shuffle to put it in random order, and then picking from the list (with .pop() or similar) until it is empty is the way to go. You can then refill and re-shuffle the list for a new (but different) "fair" order.
(Note that this kind of thing is why it is important to figure out what you want before going about "how to get there".)
The idea is. To pick random number from LIST(A) And each time it picks random number from LIST(A) the LIST(A) gets smaller. So you cant repeat. If Python pics '2' first time. It can't do it second time because '2' is not in LIST(A) ...
import random
random_numbers = [1,2,3,4,5]
X = []
while True:
one = random.choice(random_numbers))
# print(one)
if str(one) not in X:
X.append(str(one))
break
if '2' in X:
print("Last number was 2 with out repeating!")
print("You did it u pick random numbers one by one with out repeating")
random_numbers.remove(one)
print(X)
I suggest use a recursion function.
import random
def randint_exc(start, end, exception):
res = random.randint(start, end)
if res != exception:
return res
else:
return randint_exc(start, end, exception)
test = randint_exc(1, 4, 1)
print(test)
# results will be 2 or 3 or 4
For variable number of exception, you can use *args argument.
def randint_exc(start, end, *exception):
res = random.randint(start, end)
if res not in exception:
return res
else:
return randint_exc(start, end, *exception)
test1 = randint_exc(1, 4, 1)
print(test1)
# results will be 2 or 3 or 4
test2 = randint_exc(1, 4, 1, 2)
print(test2)
# results will be 3 or 4
Or you can use list for more easy-reading.
def randint_exc(start, end, exception_list):
res = random.randint(start, end)
if res not in exception_list:
return res
else:
return randint_exc(start, end, exception_list)
test1 = randint_exc(1, 4, [1])
print(test1)
# results will be 2 or 3 or 4
test2 = randint_exc(1, 4, [1, 2])
print(test2)
# results will be 3 or 4