How do I take UNIQUE random choice from two lists - python

I have two lists that defines a card
values = ['A', 'K', 'Q', 'J', '10', '9', '8', '7', '6', '5', '4', '3', '2']
marks = ['spade', 'hearts', 'diamond', 'club']
I want to have 12 unique cards, so my output should look like
('9', 'diamond')
('K', 'hearts')
('Q', 'hearts')
('7', 'spade')
('A', 'diamond')
('3', 'diamond')
('Q', 'diamond')
('3', 'hearts')
('7', 'hearts')
('2', 'diamond')
('2', 'hearts')
('5', 'spade')
I have used random choice to get this far, my code is here
count = 0
while count != 12:
value = random.choice(values)
mark = random.choice(marks)
card = Card(value, mark)
# I have a class named Card, generate() returns a tuple of mark and value for card
print(card.generate())
count += 1
But it does not provide me unique values. Please let me know or through me a resource to learn how to get unique value by random choice from two lists.

First, combine the marks and values to actual cards using itertools.product, then just random.shuffle the stack of cards and pop cards into the player's hand, like you would in real life.
import itertools, random
cards = list(itertools.product(values, marks))
random.shuffle(cards)
hand = [cards.pop() for _ in range(12)]
At the same time, this will remove the cards from the stack, and thus ensure that cards are unique across the different players' hands. If you do not want this, use random.sample instead. This way, cards are unique within one hand, but not across hands, as they remain in the stack (in this case, the shuffle step is not needed, either):
hand = random.sample(cards, 12)

What i would recommend is using random.sample(population, k) this will return a unique k items from the list population.
However for this you first need to make all the cards and then have all the cards in the list population.
Another solution would be to add a list chosen_cards and implement an equals funcion and do a check in the chosen_cards before you add the new random card to the chosen_cards.

You can do:
cards = [(v, m) for (v, m) in zip(values * 4, marks * 13)]
random.sample(cards, 12)
# RESULT
[('K', 'diamond'),
('K', 'spade'),
('3', 'spade'),
('6', 'hearts'),
('10', 'spade'),
('9', 'hearts'),
('3', 'club'),
('8', 'hearts'),
('Q', 'spade'),
('Q', 'hearts'),
('6', 'club'),
('J', 'diamond')]

Related

Atributting values to specific numbers trough a file

My question is if there's any way to attribute the numbers in the first column to the ones in the second column. So that I can read the numbers in the second column but have them connected to the ones in the first column in some way, so that I can sort them as I do in the sorted_resistances list but after sorting them I replace them with the values in the first column that we're assigned to each of the values.
For information in the code it's opening up from a file the list that's why it's programed like that
1 30000
2 30511
3 30052
4 30033
5 30077
6 30055
7 30086
8 30044
9 30088
10 30019
11 30310
12 30121
13 30132
with open("file.txt") as file_in:
list_of_resistances = []
for line in file_in:
list_of_resistances.append(int(line.split()[1]))
sorted_resistances = sorted(list_of_resistances)
If you want to keep the correlation between the values in the two columns, you can keep all of the values from each line in a tuple (or list), and then sort the list of tuples using a specific piece by passing a lambda function to the key parameter of the sorted() function that tells it to use the second piece of each tuple as the sort value.
In this example, I used pprint.pprint to make the output the of the lists easier to read.
from pprint import pprint
with open("file.txt") as file_in:
list_of_resistances = []
for line in file_in:
list_of_resistances.append(tuple(line.strip().split(' ')))
print("Unsorted values:")
pprint(list_of_resistances)
sorted_resistances = sorted(list_of_resistances, key=lambda x: x[1])
print("\nSorted values:")
pprint(sorted_resistances)
print("\nSorted keys from column 1:")
pprint([x[0] for x in sorted_resistances])
Output:
Unsorted values:
[('1', '30000'),
('2', '30511'),
('3', '30052'),
('4', '30033'),
('5', '30077'),
('6', '30055'),
('7', '30086'),
('8', '30044'),
('9', '30088'),
('10', '30019'),
('11', '30310'),
('12', '30121'),
('13', '30132')]
Sorted values:
[('1', '30000'),
('10', '30019'),
('4', '30033'),
('8', '30044'),
('3', '30052'),
('6', '30055'),
('5', '30077'),
('7', '30086'),
('9', '30088'),
('12', '30121'),
('13', '30132'),
('11', '30310'),
('2', '30511')]
Sorted keys from column 1:
['1', '10', '4', '8', '3', '6', '5', '7', '9', '12', '13', '11', '2']

zip() isnt working the way it is supposed to

guys see the code and the output i got
import itertools as it
ranks = ['A', 'K', 'Q', 'J', '10', '9', '8', '7', '6', '5', '4', '3', '2']
suits = ['H', 'D', 'C', 'S']
cards = it.product(ranks,suits)
l = []
for i in range(5):
l.append(it.islice(cards,2))
print(list(zip(*l)))
[(('A', 'H'), ('A', 'D'), ('A', 'C'), ('A', 'S'), ('K', 'H')), (('K', 'D'), ('K', 'C'), ('K', 'S'), ('Q', 'H'), ('Q', 'D'))]
This is the output i got
but shouldnt the output be like below
[(('A', 'H'), ('A','C') ,('K', 'H'),('K', 'C'),('Q', 'H')) , (('A', 'D'), ('A', 'S'), ('K', 'D'), ('K', 'S') , ('Q', 'D'))] this is the expected output
i dont know why zip function is working like this here , can someone help please
To get the desired result, you need to convert the islice object to list l.append(list(it.islice(cards,2))):
import itertools as it
ranks = ['A', 'K', 'Q', 'J', '10', '9', '8', '7', '6', '5', '4', '3', '2']
suits = ['H', 'D', 'C', 'S']
cards = it.product(ranks,suits)
l = []
for i in range(5):
l.append(list(it.islice(cards,2))) # here
print(list(zip(*l)))
Prints:
[(('A', 'H'), ('A', 'C'), ('K', 'H'), ('K', 'C'), ('Q', 'H')), (('A', 'D'), ('A', 'S'), ('K', 'D'), ('K', 'S'), ('Q', 'D'))]
This is rather difficult topic but the key idea is that islice and zip function are 'lazy', which means they are efficient. (These functions access elements one-by-one and cannot go backwards. In comparison, constructing a whole list in advance is expensive operation)
You have made "l" a list of 5 iterators.
It doesn't imply that first element of "l" would represent the first 2 tuples(1st&2nd) of the product, and second element of "l" would represent the next 2 tuples(3rd&4th) etc. They are just 5 iterators on the product 'cards'.
Now zip function is executed on 5 elements of list "l".
To compute the first zipped element, lazy 5 iterators are sequentially executed.
First iterator(=l[0]) takes the first element of 'cards' (=AH)
Second iterator(=l[1]) takes the second element of 'cards' (=AD)
.. and so on.
That explains your output.
Now here's another interesting idea.
what if you put a print("cards: ", list(card)) line
after the initialization of variable 'cards'? would it change the output of the code?
It's just a print statement so intuitively it shouldn't change the behavior of program apart from printing some line. But it does.
import itertools as it
ranks = ['A', 'K', 'Q', 'J', '10', '9', '8', '7', '6', '5', '4', '3', '2']
suits = ['H', 'D', 'C', 'S']
cards = it.product(ranks,suits)
print("cards: ", list(cards)) ''' comment this line to get your original output,
uncomment to make list(zip(*l)) return [] '''
l = []
for i in range(5):
l.append(it.islice(cards,2))
print(l)
print("zip: ", list(zip(*l)))
why is list(zip(*l)) empty list now?
While printing 'list(cards)' we used the iterator on 'cards' until it reached the StopIteration. This is because we made the whole list of it.
since we used it, the next(iter(cards)) will raise StopIteration error.
Therefore, when elements of list "l" try to iterate over 'cards', they can't because it's already at the end of iteration. (StopIteration)
What we should learn from this is that iterators are very tricky to use, but they are powerful when used correctly. Just like pointers and memory allocations are dangerous but powerful, same goes for iterator and generators. When you reuse iterator of an object over and over(in this case iterator on cards was reused a lot), it is good to make a solid list of the results and save it, rather than leave it as a floating, dangerous iterators.

two list integer combine together in python

I am trying to get integers value from a list of specific functions in a two different list and then try to store both list integer with combination of 2nd list integer.
let suppose we have two list,
list1 = ['A(0)','B(1)','C(3)','Z(4)','Z(7)','Z(2)', 'X(3)','X(2)',...]
list2 = ['A(0)','B(1)','C(3)','Z(7)','Z(3)','Z(5)', 'X(11)','X(4)',...]
now only the integer of Z from list1 and list2 will extract and store like this sequence,
Z1 = A(4,7)
Z1 = A(7,3)
Z2 = B(2,5)
first element of list1 and 2nd element of list2 in a sequence.
here is my code which i tried,
for line in list1:
if 'OUTPUT' in line:
print(line.split('Z(')[1].split(')')[0].strip())
for line in list2:
if 'OUTPUT' in line:
print(line.split('Z(')[1].split(')')[0].strip())
here is output
4 7 7 3 2 5
but still i didnt get value like,
Z1 = A(4,7)
Z1 = A(7,3)
Z2 = B(2,5)
def format_list(lst):
new = []
for sub in lst:
open_p = sub.index("(")
close_p = sub.index(")")
letter = sub[:open_p]
number = sub[open_p + 1 : close_p]
new.append((letter, number))
return new
list1 = ["A(0)", "B(1)", "C(3)", "Z(4)", "Z(7)", "Z(2)", "X(3)", "X(2)"]
list2 = ["A(0)", "B(1)", "C(3)", "Z(7)", "Z(3)", "Z(5)", "X(11)", "X(4)"]
lst1 = format_list(list1)
lst2 = format_list(list2)
The above code will format the lists as so:
lst1 = [('A', '0'), ('B', '1'), ('C', '3'), ('Z', '4'), ('Z', '7'), ('Z', '2'), ('X', '3'), ('X', '2')]
lst2 = [('A', '0'), ('B', '1'), ('C', '3'), ('Z', '7'), ('Z', '3'), ('Z', '5'), ('X', '11'), ('X', '4')]
From there, you'll be able to use filter() to find the places in which the numbers differentiate:
different_obj = list(filter(lambda x: x[0][1] != x[1][1], zip(lst1, lst2)))
print(different_obj)
Or if you rather, you don't need to use filter:
different_obj = []
for x, y in zip(lst1, lst2):
if x[1] != y[1]:
different_obj.append((x, y))
outputs:
[(('Z', '4'), ('Z', '7')),
(('Z', '7'), ('Z', '3')),
(('Z', '2'), ('Z', '5')),
(('X', '3'), ('X', '11')),
(('X', '2'), ('X', '4'))]
From there you should be able to organize different_obj to your goal.

Round off some values of a tuple

I have tuples like this ( I not sure will it call a list of tuple or not ! )
ratings = [('5', 45.58139534883721), ('4', 27.44186046511628), ('3', 20.0), ('2', 5.116279069767442), ('1', 1.8604651162790697)]
I want to make second value round off ( or truncate, don't matter to me )up to 2 decimal place, like this:
[('5', 45.58), ('4', 27.44), ('3', 20.0), ('2', 5.11), ('1', 1.86)]
I tried something like this:
l = tuple([round(x,2) if isinstance(x, float) else x for x in ratings])
But this seems to be not working. What can I try?
Round the 2nd element of your tuples only:
ratings = [('5', 45.58139534883721), ('4', 27.44186046511628), ('3', 20.0), ('2', 5.116279069767442), ('1', 1.8604651162790697)]
l = [(item[0],round(item[1],2)) for item in ratings]
# [('5', 45.58), ('4', 27.44), ('3', 20.0), ('2', 5.12), ('1', 1.86)]

Why am I not getting the result of sorted function in expected order?

print activities
activities = sorted(activities,key = lambda item:item[1])
print activities
Activities in this case is a list of tuples like (start_number,finish_number) the output of the above code according to me should be the list of values sorted according the the increasing order of finish_number. When I tried the above code in shell I got the following output. I am not sure why the second list is not sorted according the the increasing order of the finish_number. Please help me in understanding this.
[('1', '4'), ('3', '5'), ('0', '6'), ('5', '7'), ('3', '9'), ('5', '9'), ('6', '10'), ('8', '11'), ('8', '12'), ('2', '14'), ('12', '16')]
[('6', '10'), ('8', '11'), ('8', '12'), ('2', '14'), ('12', '16'), ('1', '4'), ('3', '5'), ('0', '6'), ('5', '7'), ('3', '9'), ('5', '9')]
You are sorting strings instead of integers: in that case, 10 is "smaller" than 4. To sort on integers, convert it to this:
activites = sorted(activities,key = lambda item:int(item[1]))
print activities
Results in:
[('1', '4'), ('3', '5'), ('0', '6'), ('5', '7'), ('3', '9'), ('5', '9'), ('6', '10'), ('8', '11'), ('8', '12'), ('2', '14'), ('12', '16')]
Your items are being compared as strings, not as numbers. Thus, since the 1 character comes before 4 lexicographically, it makes sense that 10 comes before 4.
You need to cast the value to an int first:
activities = sorted(activities,key = lambda item:int(item[1]))
You are sorting strings, not numbers. Strings get sorted character by character.
So, for example '40' is greater than '100' because character 4 is larger than 1.
You can fix this on the fly by simply casting the item as an integer.
activities = sorted(activities,key = lambda item: int(item[1]))
It's because you're not storing the number as a number, but as a string. The string '10' comes before the string '2'. Try:
activities = sorted(activities, key=lambda i: int(i[1]))
Look for a BROADER solution to your problem: Convert your data from str to int immediately on input, work with it as int (otherwise you'll be continually be bumping into little problems like this), and format your data as str for output.
This principle applies generally, e.g. when working with non-ASCII string data, do UTF-8 -> unicode -> UTF-8; don't try to manipulate undecoded text.

Categories

Resources