Choosing random integers except for a particular number for python? - python

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

Related

"Homemade" infinite precision sum function

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)

Generate 4 digits number but excluding all the numbers with any 0

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)

Hard to understand the dynamic programming part of Leetcode question 494, Target Sum

I found this solution which is extremely fast(beats 99.5%) and space-saving(beats 95%) at the same time.
I understand most part, except the line: dp[j]=dp[j]+dp[j-num]
I understand the w is calculating the sum of all numbers with '+' sign.
Can anyone explain what this part means? dp[j]=dp[j]+dp[j-num]
Here is the code:
class Solution:
def findTargetSumWays(self, nums: List[int], S: int) -> int:
w=(S+sum(nums))//2
if (S+sum(nums))%2==1: return 0
if sum(nums)<S: return 0
dp=[0]*(w+1)
dp[0]=1
for num in nums:
for j in range(w,num-1,-1):
dp[j]=dp[j]+dp[j-num]
return dp[-1]
Here is the question:
You are given a list of non-negative integers, a1, a2, ..., an, and a target, S. Now you have 2 symbols + and -.
For each integer, you should choose one from + and - as its new symbol.
Find out how many ways to assign symbols to make sum of integers equal to target S.
Example 1:
Input: nums is [1, 1, 1, 1, 1], S is 3.
Output: 5
Explanation:
-1+1+1+1+1 = 3
+1-1+1+1+1 = 3
+1+1-1+1+1 = 3
+1+1+1-1+1 = 3
+1+1+1+1-1 = 3
There are 5 ways to assign symbols to make the sum of nums be target 3.
Sahadat's answer is correct but may not be comprehensive enough for OP. Let me add more details. The mathematical equivalent question is how to choose certain elements from the list to sum to w (no changing signs). This question is however easier to deal with in DP.
IN particular, d[0]=1 since we have unique way to reach 0 (by choosing no element). After that, inductively, for each num we process, we know the number of solutions to reach j is either d[j] (meaning we DO NOT choose num) or d[j-num] (meaning we do choose num). Once we go over all nums in the list, d[w] will contain the number of solutions to reach w. This is also the solution to the original question.
Rather than attempting to theorize about why this works, I'm just gonna walk through the logic and describe it.
In your example, nums = [1, 1, 1, 1, 1]
w=(S+sum(nums))//2 # in your example this is 4
dp=[0]*(w+1) # your array is 5 elements long, its max index is w
dp[0]=1 # initialize first index to 1, everything else is 0
for num in nums: # num will be 1 for 5 iterations
for j in range(w,num-1,-1): # j starts at the end and iterates backward.
# here j goes from index 4 to 0 every time
dp[j]=dp[j]+dp[j-num]. # remember dp = [1, 0, 0, 0, 0]. but after
# the first completion of the inner loop, dp
# will be [1, 2, 0, 0, 0]. remember you have
# negative indices in this language.
return dp[-1] # so after all iterations... dp is [1, 2, 3, 4, 5]
you're just kind of pushing that initial 1 - i.e. dp = [1, 0, 0, 0, 0] - toward the end of the array. And this is happening in a way that is dependent on the size of num is, at each iteration.
Why does this work? Let's try a different example and see the contrast.
Let's say nums = [7, 13] and S is 20. The answer should be 1, right? 7 + 13 = 20, that's all that is possible.
w=(S+sum(nums))//2 # now this is 20.
dp=[0]*(w+1) # your array is 21 elements long, its max index is w
dp[0]=1 # initialize first index to 1, everything else is 0
for num in nums: # so num will be 7, then 13, 2 iterations
for j in range(w,num-1,-1): # j starts at the end and iterates backward.
# on first iteration j goes from index 20 to 6
# on 2nd iteration j goes from index 20 to 12
dp[j]=dp[j]+dp[j-num]. # so when num = 7, and you reach the 2nd last
# iteration of the inner loop... index 7
# you're gona set dp[7] to 1 via dp[7]+dp[0]
# subsequently, when num = 13... when you're
# at dp[20] you'll do dp[20] = d[20]+d[7].
# Thus now dp[20] = 1, which is the answer.
return dp[-1]
So the larger num is... the more you skip around, the less you move 1s up to the top. The larger num values disperse the possible combinations that can add up to a given S. And this algorithm accounts for that.
But notice the manner in which the 1 at dp[0] was moved up to dp[20] in the final example. It was precisely because 7 + 13 = 20, the only combination. These iterations and summations account for all these possible combinations.
But how are potential sign flips accounted for in the algorithm? Well, let's say S was not 20 in the previous, but it was 6. i.e. 13 - 7 = 6, the only solution. Well... lets look at that example:
w=(S+sum(nums))//2 # now this is 13. (20+6)/2 = 13.
dp=[0]*(w+1) # your array is 14 elements long
dp[0]=1 # initialize first index to 1 again
for num in nums: # so num will be 7, then 13, 2 iterations
for j in range(w,num-1,-1):
# j starts at the end and iterates backward.
# on first iteration j goes from index 13 to 6
# on 2nd iteration j goes from index 13 to 12
dp[j]=dp[j]+dp[j-num].
# so this time, on the 2nd iteration, when
# num = 13... you're at dp[13]
# you'll do dp[13] = d[13]+d[0].
# Thus now dp[13] = 1, which is the answer.
# This time the 1 was moved directly from d0 to the end
return dp[-1]
So this time, when the combination included a negative number, it was the size of w being 13 that led to the solution: the index d[13] + d[0] = 1. The array size was smaller such that the larger number added with 1 directly.
It's quite odd, I will admit, you have 2 different mechanisms working depending on how what the signs are, potentially. In the case of a positive and negative number summing to S, it was the smaller overall array length that led to the 1 moving to the final slot. For 2 positive numbers... there was this intermediary moving the 1 up that happened. But at least you can see the difference...

Why control is going inside if condition while the condition is false

Function to find minimum number of eliminations such that sum of all adjacent elements is even:
def min_elimination(n, arr):
countOdd = 0
# Stores the new value
for i in range(n):
# Count odd numbers
***if (arr[i] % 2):
countOdd += 1***
# Return the minimum of even and
# odd count
return min(countOdd, n - countOdd)
# Driver code
if __name__ == '__main__':
arr = [1, 2, 3, 7, 9]
n = len(arr)
print(min_elimination(n, arr))
Please help me with the if condition. When the code does if(number%2) then control is going inside the if since the first element of list is an odd number. Is there any difference between if(number%2) and if(number%2==0). Because when I tried if(number%2==0) control didn't go inside the if as the number was odd (check first element of the list).
This is a simple version of the above.
def min_elimination(arr):
lst1 = [n for n in arr if n%2] # List of all odd numbers
lst2 = [n for n in arr if not n%2] # List of all even numbers
lst = max(lst1, lst2, key=lambda x: len(x))
return lst
print(min_elimination([1, 2, 3, 7, 9]))
I believe your code works fine as-is. It correctly returns the minimum number of eliminations necessary to achieve the result, not the result itself.
is there any difference between if(number%2) and if(number%2==0)
Yes, if number % 2 is the same as saying if number % 2 == 1, which is the opposite of saying if number % 2 == 0. So switching one for the other will break your program's logic.
I might simplify your code as follows:
def min_elimination(array):
odd = 0
# Stores the new value
for number in array:
# Count odd numbers
odd += number % 2
return min(odd, len(array) - odd)
Where min_elimination([1, 2, 3, 7, 9]) returns 1, there is one (1) elimination necessary to make the sum of all adjacent elements even.
The only way two integers can add up to be even is that both integers should be odd, or both integers should be even. So your question basically wants to find whether there are more odd number in the array, or even numbers:
def min_elimination(arr):
return len(min([n for n in arr if n%2],[n for n in arr if not n%2],key=len))
print(min_elimination([1, 2, 3, 7, 9]))
Output:
1
You can use numpy to compare the number of odd numbers in the array to the number of even numbers in the array:
import numpy as np
def min_elimination(arr):
return len(min(arr[arr%2],arr[any(arr%2)],key=len))
print(min_elimination(np.array([1, 2, 3, 7, 9])))
Output:
1

The number of ways to find unique numbers that sum to a number in Python

This is the description of the problem:
There is a list of integers, sequence. There is another integer argument, target. The objective is to return the number of unique ways target can be expressed as the sum of four distinct numbers in sequence.
This is my code:
def __main__(sequence, target):
big = 0
for elem in sequence:
for elem_ in sequence:
for _elem_ in sequence:
for _elem__ in sequence:
if (elem + elem_ + _elem_ + _elem__ == target):
big+=1
print(str(big))
__main__([2, 1, 1, 1, 2, 1, 2, 2, 1], 6)
The algorithm seems fine to me. But I keep getting the answer 2400 for this, when according to the test case, the answer should be 60. I suspect I'm going over one method four times, but then again dividing 2400 by 4 does not give you 60.
You can use itertools.combinations():
import itertools
def sums(lst, n):
count = 0
for sample in list(itertools.combinations(lst, 4)):
if sum(sample) == n:
count += 1
return count
print(sums([2, 1, 1, 1, 2, 1, 2, 2, 1], 6)) # => 60
From the docs:
Return r length subsequences of elements from the input iterable.
Combinations are emitted in lexicographic sort order. So, if the input iterable is sorted, the combination tuples will be produced in sorted order.
Elements are treated as unique based on their position, not on their value. So if the input elements are unique, there will be no repeat values in each combination.
combinations(range(4), 3) # --> 012 013 023 123
Here's one way to do it:
def sums(sequence, target):
n = len(sequence)
total = 0
for i1 in range(n):
v1 = sequence[i1]
for i2 in range(i1+1, n):
v2 = sequence[i2]
for i3 in range(i2+1, n):
v3 = sequence[i3]
for i4 in range(i3+1, n):
v4 = sequence[i4]
if v1+v2+v3+v4 == target:
total += 1
return total
def main():
print(sums([2, 1, 1, 1, 2, 1, 2, 2, 1], 6))
main()
This ensures that each list element is used at most once, and gives the desired result of 60.
The looping is a little less concise than I'd like, but it's efficient, and doesn't require any temporary list slices.

Categories