Fast bit string generation given indices - python-3.x

Here a is a list, for example [34, 52, 57].
The function takes in this list and creates a bit string of length 64, where every index is a 0 except at the given indices.
So it would look like [0,0,....1,...1,..1,..0,0,0] where only at indices [34, 52, 57] we have ones.
def bit_string_gen(a):
bit_string = []
for key, value in enumerate(range(64)):
if key in a:
bit_string.append(1)
else:
bit_string.append(0)
return bit_string
Is there a better way to do this, maybe using lambda or map or itertools instead of enumerate.

The problem with your approach is that you:
use an if statement for every bit; and
use the in test which can be rather expensive.
A beter method can be:
def bit_string_gen(a):
bit_string = [0]*64
for value in a:
bit_string[value] = 1
return bit_string
So here you iterate only over the values of a, and you set these bits to 1.
Nevertheless it is a bit weird to encode this with a list of ints. A more compact way to do this is to encode this binary on an integer. For instance by using:
def bit_string_gen(a):
bit_string = 0
for value in a:
bit_string |= 1 << value
return bit_string
So in the last case if you set the bits like in your sample input, you obtain:
>>> bin(bit_string_gen([34, 52, 57]))
'0b1000010000000000000000010000000000000000000000000000000000'
>>> hex(bit_string_gen([34, 52, 57]))
'0x210000400000000'

If you're looking for a solution using map/lambda, here's a one-liner:
map(lambda x: 1 if x in [34, 52, 57] else 0, range(0, 64))

Related

Python function removing items form list, dropping unexpected elements

It's a simple code practice challenge that asks that I make a function that takes a list of mixed types and returns only the integers
def return_only_integer(lst):
for i in lst:
if type(i) != int:
lst.remove(i)
return lst
That's it, it seems simple enough but the tests are coming back negative:
return_only_integer([9, 2, "space", "car", "lion", 16])
Returns: [9, 2, 'car', 16]
return_only_integer(["hello", 81, "basketball", 123, "fox"])
Returns what it should: [81, 123]
return_only_integer([10, "121", 56, 20, "car", 3, "lion"])
Also returns what it should: [10, 56, 20, 3]
but:
return_only_integer(["String", True, 3.3, 1])
Returns: [True, 1]
The code is so simple and straightforward, I have no idea why these 2 tests are failing.
Why would 'car' even be in the first list but the other strings not?
type(True) is bool, why is it there?
This is probably due to you modifying the list in the conditional. By removing an item from the list, you are likely shifting the iteration in that operation.
It may be worth looking into filter() instead.
https://docs.python.org/3/library/functions.html#filter
You can create a temporary list inside your function to hold the items that are integers. Once you have processed all the items, you can return the temporary list as part of your return statement. If there are no integers, you can return None.
def return_only_integer(lst):
int_lst = []
for i in lst:
if type(i) == int:
int_lst.append(i)
return int_lst if int_lst else None
print (return_only_integer([9, 2, "space", "car", "lion", 16]))
print (return_only_integer(['ball', True, "space", "car", "lion", 'fish']))
This will output as follows:
[9, 2, 16]
None
def return_only_integer(lst):
for i in lst:
if type(i) != int:
lst.remove(i)
return lst
THIS FUNCTION HAS VERY BIG FAULT.
consider this list [9, 2, "space", "car", "lion", 16]
when it had removed "space" then your i had directly reached to lion and it ignored car because your list is changed and your i index is not changed. so it is moving as it is.
after removing one non integer, you must make sure to change the index position of i. so try this code. it will work.
def return_only_integer(lst):
for i in lst:
#print(i,type(i))
if type(i) != int:
#print("flag this is not integer ",i)
lst.remove(i)
return_only_integer(lst)
return(lst)
print(return_only_integer(["hello", 81, "basketball", 123, "fox"]))
hope u understand. if you didn't understand then tell me .
Indeed you should not change the list you are iterating on, it produces unexpected results. Item deleted leaves room for the next, without the latter being picked in the iteration (so not being dropped in your example).
The possible choices to perform such task involve the usage of another list. A possible solution is very familiar to python developers:
def return_only_integer(lst):
return [i for i in lst if type(i) == int]

python random lottery number generator game

I have to make a game where like the lottery my program generates 5 random numbers from a list of numbers 1-50 and one additional number from a list of numbers 1-20 and combines them into a final list that reads eg: (20, 26, 49, 01, 11, + 06) where two numbers are never repeated like (22, 11, 34, 44, 01, + 22) <--- this is what I don't want
attached below is the code I have written yet how do I make it so two numbers or more are never repeated and to add the + into my list without the "" signs
input:
import random
a = list(range(1,51))
b = random.randint(1, 20)
temp = []
for i in range(5):
random.shuffle(a)
temp.append(random.choice(a[:5]))
temp.append('+')
temp.append(b)
print(temp)
output:
[14, 12, 3, 16, 23, '+', 9]
You can not add + without the ' around them - they mark the + as string.
Also: you shuffle your list - simply take the first 5 values - they are random and your list does not contain any dupes so you are golden:
nums = list(range(1,51))
random.shuffle(nums)
five_nums = nums[:5]
print(five_nums) # [44, 23, 34, 38, 3]
To simplyfy it, use:
import random
# creates 5 unique elements from 1..50 and adds a + and a [0-19]+1 number
randlist = random.sample(range(1,51),k=5) + ["+", random.choice(range(20))+1]
print(randlist)
Now you got mixed numbers and strings - you can create a combined string by:
print("You drew {} {} {} {} {} {} {}".format(*randlist))
To create a string like
[48, 2, 9, 6, 41, '+', 8]
You drew 48 2 9 6 41 + 8
Doku:
random.sample (draw without putting back)
You can try the following:
import random
randList, run = [], 0
while run < 6:
number = random.randint(1,51)
if number not in randList:
if run == 5:
randList.append('+'+str(number))
break
randList.append(number)
run += 1
print(randList)
You can't have a string in a list without quotes, however, if you were to print every item in the list (using a for loop or join), the quotes wouldn't be there.
This code will generate a list of 7 random numbers
import random
def main():
numbers = []
for num in range(7):
num = random.randrange(50)
numbers.append(num)
print(numbers)
main()
#No repeating numbers and sorted output
import random
picks = int (input("How Many Picks ?: "))
for i in range (picks):
num_list = random.sample(range(1, 45), 5,)
num_list.sort()
joker_num = random.sample(range(1, 20), 1)
print("Lucky Numbers :", num_list, "-", "Joker :", joker_num)
It didn't work because you need to have
import random

Getting a random choice from an array

I tried using the random.choice command and it seems to not work.
The Wolf has already been assigned to mob
class Wolf(Character):
def __init__(self):
super().__init__(name="wolf",hp=7,atk=6,df=4,inventory={},spells=
{"bite": randint(3,6)},exp=8)
c = random.choice(mob.spells)
spower = mob.spells[c]
ad = mob.atk / hero.df
damage = ad * spower
damage = int(round(damage))
random.choice wont work because you are passing a dictionary and it expects something that can be indexed using integer indices. Choosing randomly from a dictionary could work if the keys are integers.
d = {'a': 10, 'b': 20}
random.choice(d)
The above code will fail, but this will work:
d = {1: 10, 0: 20}
random.choice(d)
Its not magic, it works because the code in random.choice chooses a random integer between 0 and len(obj) and return the object at that index. The code below will never work:
d = {-1: 10, 2: 20}
random.choice(d)
And this will work sometimes:
d = {'a': 10, 0: 20}
random.choice(d)
It doesnt make any sense to find a random index in a dictionary.
For getting a random key in a dictionary do this:
d = {'a': 10, -1: 20, 90: -90}
random_key = random.choice(list(d))
In your case, the code will be:
c = random.choice(list(mob.spells))

Python: Use a for loop to get Nth number out of a list

I need to get every 3rd value out of a list and add it to a new list.
This is what I have so far.
def make_reduced_samples(original_samples, skip):
skipped_list = []
for count in range(0, len(original_samples), skip):
skipped_list.append(count)
return skipped_list
skip is equal to 3
I get the indexes and not the value of the numbers in the list.
It gives me [0,3,6]. Which are the indexes in the list and not the value of the indexes.
The example I am given is:
In this list [12,87,234,34,98,11,9,72], you should get [12,34,9].
I cannot use skipped_list = original_samples[::3] in any way.
You need to append the value of the original_samples array at the index. Not the index (count) itself.
def make_reduced_samples(original_samples, skip):
skipped_list = []
for count in range(0, len(original_samples), skip):
skipped_list.append(original_samples[count])
return skipped_list
The correct, most pythonic, and most efficient way to do that is to use slicing.
lst = [12, 87, 234, 34, 98, 11, 9, 72]
skipped_list = lst[::3]
print(skipped_list) # [12, 34, 9]
If the step does not obey a linear relation (which it does here), then you could use a list-comprehension with enumerate to filter on the index.
skipped_list = [x for i, x in enumerate(lst) if i % 3 == 0]
print(skipped_list) # [12, 34, 9]
One liner:
skipped_list = [j for (i,j) in enumerate(original_samples, start=1) if i % 3 == 0]

Get a list of all number in a certain range containing only certain digits without checking each number

Is there a way to create a list of all numbers less than 10,000 that do not contain any of the digits 0, 2, 4, 5, 6, 8? Of course one can simply type something like:
bads = ['0', '2', '4', '5', '6', '8']
goods = []
for n in range(1, 10000, 2):
if not any(bad in str(n) for bad in bads):
goods.append(n)
However, I'm looking for a method which instead considers the digits 1, 3, 7, 9 and creates all possible unique strings of permutations of these numbers of size 4 or less, duplicate digits allowed. Does itertools, for example, have something that would easily do this? I looked at the permutations method, but that doesn't produce numbers with repeated digits from the collection, and the product method doesn't seem to be what I'm after either, given that it simply would return Cartesian products of 1, 3, 5, 7 with itself.
Here's a simple-minded approach using permutations and combinations_with_replacement from itertools:
from itertools import permutations, combinations_with_replacement
def digit_combinations(power_of_ten):
numbers = set()
for n in range(1, power_of_ten + 1):
for combination in combinations_with_replacement("1379", n):
numbers |= set(permutations(combination, len(combination)))
return sorted(int(''.join(number)) for number in numbers)
print(digit_combinations(4))
OUTPUT
[1, 3, 7, 9, 11, 13, 17, 19, ..., 9971, 9973, 9977, 9979, 9991, 9993, 9997, 9999]
It could be made more space efficient using generators, but depending on the range, it might not be worth it. (For up to 10,000 there are only 340 numbers.) For numbers to 10^4, this code takes roughly as long as your simple example. But for 10^7, this code runs over 40x faster on my system than your simple example.
Could you include your idea for the generator?
Here's a basic rework of the code above into generator form:
from itertools import permutations, combinations_with_replacement
def digit_combinations_generator(power_of_ten):
for n in range(1, power_of_ten + 1):
for combination in combinations_with_replacement("1379", n):
for number in set(permutations(combination, len(combination))):
yield int(''.join(number))
generator = digit_combinations_generator(4)
while True:
try:
print(next(generator), end=', ')
except StopIteration:
print()
break
This does not return the numbers sorted, it just hands them out as fast as it generates them.

Resources