Removing matching items from a list?

K

kevin4fong

Basically, I'm trying to find out how to remove matching items from a list. But there doesn't seem to be any information on how to go about doing this specific function.

For example, what I want is:

let's say there is a list:

pHands[0] = ['ad', 'ac', 'as', 'ah', '7d', '8s', '9d', 'td', 'js', 'jd']

So up there, my list, which is named pHands[0] has ten items in it.

I'm trying to make a function where a search is initiated into the list and any matching items with a first matching number/letter reaching four are removed

So in the end, ad, ac, as, ah (the four a's) will all be deleted/removed from the list. I need the list to automatically detect if there are four matching first letter/numbers in the items in the list.

The remaining list will be: pHands[0] = ['7d', '8s', '9d', 'td', 'js', 'jd']
 
K

kevin4fong

Basically, I'm trying to find out how to remove matching items from a list. But there doesn't seem to be any information on how to go about doing this specific function.



For example, what I want is:



let's say there is a list:



pHands[0] = ['ad', 'ac', 'as', 'ah', '7d', '8s', '9d', 'td', 'js', 'jd']



So up there, my list, which is named pHands[0] has ten items in it.



I'm trying to make a function where a search is initiated into the list and any matching items with a first matching number/letter reaching four are removed



So in the end, ad, ac, as, ah (the four a's) will all be deleted/removed from the list. I need the list to automatically detect if there are four matching first letter/numbers in the items in the list.



The remaining list will be: pHands[0] = ['7d', '8s', '9d', 'td', 'js', 'jd']

Ah, I forgot to mention. This function will be used for other lists to so it can't specifically target "a" and needs to auto search for four matching first letters.

If it helps, the two letters/numbers in each item are strung together by the following function:

for suite in range(4):
for rank in range(13):
deck.append(rankList[rank]+suitList[suite])

So they can be directly accessed using:
card[0] for the first letter/number
card[1] for the second
 
W

woooee

Use a dictionary to count the number of times each first letter appears, then place any first letters==4 in a list or set and remove any items that have a first letter in the list/set (or keep items that are not in the set which is probably faster if using list comprehension).
 
R

Roy Smith

let's say there is a list:

pHands[0] = ['ad', 'ac', 'as', 'ah', '7d', '8s', '9d', 'td', 'js', 'jd']

I assume this is a card game, and these are cards (ad = Ace of Diamonds,
etc).
I'm trying to make a function where a search is initiated into the list and
any matching items with a first matching number/letter reaching four are
removed

I'm not quite sure how to parse that, but I think what you're saying
(using the deck of cards model) is you want to find all the sets of 4
cards of the same rank. In the example above, you've got all four aces
(which, in the wrong saloon, can get you shot).

I think I would do something like:

-----------------------------------------
import collections

def remove_four_of_a_kind(hand):
ranks = [card[0] for card in hand]
counts = collections.Counter(ranks)
fours = [rank for rank, count in counts.items() if count == 4]
new_hand = [card for card in hand if card[0] not in fours]
return new_hand

hand = ['ad', 'ac', 'as', 'ah', '7d', '8s', '9d', 'td', 'js', 'jd']
print remove_four_of_a_kind(hand)
-----------------------------------------

$ python cards.py
['7d', '8s', '9d', 'td', 'js', 'jd']

I just gave a class yesterday where we covered list comprehensions and
Counters, so maybe I just have comprehensions on the brain today :)
 
M

MRAB

Basically, I'm trying to find out how to remove matching items from a list. But there doesn't seem to be any information on how to go about doing this specific function.

For example, what I want is:

let's say there is a list:

pHands[0] = ['ad', 'ac', 'as', 'ah', '7d', '8s', '9d', 'td', 'js', 'jd']

So up there, my list, which is named pHands[0] has ten items in it.

I'm trying to make a function where a search is initiated into the list and any matching items with a first matching number/letter reaching four are removed

So in the end, ad, ac, as, ah (the four a's) will all be deleted/removed from the list. I need the list to automatically detect if there are four matching first letter/numbers in the items in the list.

The remaining list will be: pHands[0] = ['7d', '8s', '9d', 'td', 'js', 'jd']
hands = ['ad', 'ac', 'as', 'ah', '7d', '8s', '9d', 'td', 'js', 'jd']
from collections import Counter
counts = Counter(hand[0] for hand in hands)
counts Counter({'a': 4, 'j': 2, 't': 1, '7': 1, '9': 1, '8': 1})
counts.most_common()
[('a', 4), ('j', 2), ('t', 1), ('7', 1), ('9', 1), ('8', 1)]

So there are 4 aces.
hands = [hand for hand in hands if hand[0] != 'a']
hands
['7d', '8s', '9d', 'td', 'js', 'jd']
 
S

Steven D'Aprano

Basically, I'm trying to find out how to remove matching items from a
list. But there doesn't seem to be any information on how to go about
doing this specific function.

The documentation cannot possibly cover every single one of the infinite
number of things somebody might want to do with Python. Programming is
about figuring out how to do the things you want from the tools provided
by the language.

For example, what I want is:

let's say there is a list:

pHands[0] = ['ad', 'ac', 'as', 'ah', '7d', '8s', '9d', 'td', 'js', 'jd']

So up there, my list, which is named pHands[0] has ten items in it.

Ten items? I wouldn't have known that if you didn't say so! *wink*

But seriously... you don't need to repeat obvious things like that. We
can count as well as you can.

But more importantly, it is irrelevant. Is "ten items" important to this
problem? No. What if there were nine, or thirty five, or seven? Would the
problem of "removing matching items" change? No, the problem remains the
same regardless of how many items there are.

I'm trying to make a function where a search is initiated into the list
and any matching items with a first matching number/letter reaching four
are removed

In general, rather than removing items from a list, it is faster and
safer (less error-prone) to create a new list with the items not removed.
But either way, when trying to program, start by thinking about how *you*
would do this task by hand:

1) I would start by counting how many items start with each initial
letter: in your example I would count those starting with 'a' (4),
'7' (1), and so on.

2) Then go through those initial letters, and pick out the ones equal to
4 (or should that be "four or more"?). In this case, only 'a' is 4 or
more, but there could be multiple examples, say, 4 'a's and 6 'b's.

3) Then, either delete those items from the original list, *or* make a
new list with the remaining items. Making a new list is usually better.

Now start turning each step into Python code.

Step 1:

Iterate over each item, grab the first character of that item, and add
one to a counter.

counts = {} # Start with an empty dict.
for item in pHands[0]:
c = item[0] # Grab the first character.
if c in counts:
counts[c] += 1
else:
counts[c] = 1


This sets the counter to 1 the first time each character is seen,
otherwise increments the counter by 1. There's a ready-made tool for
doing that:

from collections import Counter
counts = Counter(item[0] for item in pHands[0])

but under the hood, it's essentially doing the same thing as I wrote
above.


Steps 2 and 3 can be done together:

new_list = []
for item in pHand[0]:
c = item[0]
# Look up the character in the counter.
if counts[c] < 4:
new_list.append(item)

pHand[0] = new_list
 
R

Roy Smith

Steven D'Aprano said:
2) Then go through those initial letters, and pick out the ones equal to
4 (or should that be "four or more"?).

Assuming my earlier hunch is correct about these being cards in a deck,
and the a's being aces, I would hope it's not "four or more". See my
earlier comment about saloons and gunshot wounds.
 
C

Chris Angelico

Assuming my earlier hunch is correct about these being cards in a deck,
and the a's being aces, I would hope it's not "four or more". See my
earlier comment about saloons and gunshot wounds.

Unless he's working with multiple decks. There are plenty of games
played with a double deck. But we did get a peek at his creation code,
which appears to make but a single deck's worth of cards.

ChrisA
 
K

kevin4fong

Basically, I'm trying to find out how to remove matching items from a
list. But there doesn't seem to be any information on how to go about
doing this specific function.



The documentation cannot possibly cover every single one of the infinite

number of things somebody might want to do with Python. Programming is

about figuring out how to do the things you want from the tools provided

by the language.




For example, what I want is:
let's say there is a list:
pHands[0] = ['ad', 'ac', 'as', 'ah', '7d', '8s', '9d', 'td', 'js', 'jd']
So up there, my list, which is named pHands[0] has ten items in it.



Ten items? I wouldn't have known that if you didn't say so! *wink*



But seriously... you don't need to repeat obvious things like that. We

can count as well as you can.



But more importantly, it is irrelevant. Is "ten items" important to this

problem? No. What if there were nine, or thirty five, or seven? Would the

problem of "removing matching items" change? No, the problem remains the

same regardless of how many items there are.




I'm trying to make a function where a search is initiated into the list
and any matching items with a first matching number/letter reaching four
are removed



In general, rather than removing items from a list, it is faster and

safer (less error-prone) to create a new list with the items not removed.

But either way, when trying to program, start by thinking about how *you*

would do this task by hand:



1) I would start by counting how many items start with each initial

letter: in your example I would count those starting with 'a' (4),

'7' (1), and so on.



2) Then go through those initial letters, and pick out the ones equal to

4 (or should that be "four or more"?). In this case, only 'a' is 4 or

more, but there could be multiple examples, say, 4 'a's and 6 'b's.



3) Then, either delete those items from the original list, *or* make a

new list with the remaining items. Making a new list is usually better.



Now start turning each step into Python code.



Step 1:



Iterate over each item, grab the first character of that item, and add

one to a counter.



counts = {} # Start with an empty dict.

for item in pHands[0]:

c = item[0] # Grab the first character.

if c in counts:

counts[c] += 1

else:

counts[c] = 1





This sets the counter to 1 the first time each character is seen,

otherwise increments the counter by 1. There's a ready-made tool for

doing that:



from collections import Counter

counts = Counter(item[0] for item in pHands[0])



but under the hood, it's essentially doing the same thing as I wrote

above.





Steps 2 and 3 can be done together:



new_list = []

for item in pHand[0]:

c = item[0]

# Look up the character in the counter.

if counts[c] < 4:

new_list.append(item)



pHand[0] = new_list

Ah, all of the replies were useful but I found yours the most useful because of all the descriptions and in depth steps so I could actually understand what the code did. Thank you.

Would you also happen to know how to fit in a simple count for each set of cards that is removed?

For example, 4a's gone would set the count to 1 but if there was also 4j's, the count would be at 2.
 
S

Steven D'Aprano

Assuming my earlier hunch is correct about these being cards in a deck,
and the a's being aces, I would hope it's not "four or more". See my
earlier comment about saloons and gunshot wounds.

There are card games that involve more than four suits, or more than one
pack. In principle, if you draw ten cards from an unknown number of
packs, you could draw ten Aces, or even ten Aces of the same suit. Think
of playing blackjack with ten packs shuffled together.

Cripple Mr Onion, for example, uses hands of ten cards drawn from eight
suits:

http://discworld.wikia.com/wiki/Cripple_Mr_Onion

(yes, it's a real game, based on a fictional game)


The Indian Ganjifa deck uses ten "houses" (decks) of 12 cards each.

Pinochle uses the standard four Western suits, but uses two copies of
each card 9, 10, J, Q, K, A, for 48 cards in total. Sometimes people
combine two pinochle decks for larger games, so with a double deck all
ten cards could be Aces.

In the 1930s, there was a fad for playing Bridge with a fifth suit,
coloured green, called Royals, Leaves, Eagles or Rooks depending on the
manufacturer.

There are five- and six-suit versions of poker, with at least two still
commercially available: the five-suit Stardeck pack (which adds Stars),
and the six-suit Empire deck (which adds red Crowns and black Anchors).

There is an eight-suit Euchre pack that adds red Moons, black Stars, red
four-leaf Clovers and black Tears to the standard deck.
 
K

kevin4fong

Basically, I'm trying to find out how to remove matching items from a
list. But there doesn't seem to be any information on how to go about
doing this specific function.



The documentation cannot possibly cover every single one of the infinite

number of things somebody might want to do with Python. Programming is

about figuring out how to do the things you want from the tools provided

by the language.




For example, what I want is:
let's say there is a list:
pHands[0] = ['ad', 'ac', 'as', 'ah', '7d', '8s', '9d', 'td', 'js', 'jd']
So up there, my list, which is named pHands[0] has ten items in it.



Ten items? I wouldn't have known that if you didn't say so! *wink*



But seriously... you don't need to repeat obvious things like that. We

can count as well as you can.



But more importantly, it is irrelevant. Is "ten items" important to this

problem? No. What if there were nine, or thirty five, or seven? Would the

problem of "removing matching items" change? No, the problem remains the

same regardless of how many items there are.




I'm trying to make a function where a search is initiated into the list
and any matching items with a first matching number/letter reaching four
are removed



In general, rather than removing items from a list, it is faster and

safer (less error-prone) to create a new list with the items not removed.

But either way, when trying to program, start by thinking about how *you*

would do this task by hand:



1) I would start by counting how many items start with each initial

letter: in your example I would count those starting with 'a' (4),

'7' (1), and so on.



2) Then go through those initial letters, and pick out the ones equal to

4 (or should that be "four or more"?). In this case, only 'a' is 4 or

more, but there could be multiple examples, say, 4 'a's and 6 'b's.



3) Then, either delete those items from the original list, *or* make a

new list with the remaining items. Making a new list is usually better.



Now start turning each step into Python code.



Step 1:



Iterate over each item, grab the first character of that item, and add

one to a counter.



counts = {} # Start with an empty dict.

for item in pHands[0]:

c = item[0] # Grab the first character.

if c in counts:

counts[c] += 1

else:

counts[c] = 1





This sets the counter to 1 the first time each character is seen,

otherwise increments the counter by 1. There's a ready-made tool for

doing that:



from collections import Counter

counts = Counter(item[0] for item in pHands[0])



but under the hood, it's essentially doing the same thing as I wrote

above.





Steps 2 and 3 can be done together:



new_list = []

for item in pHand[0]:

c = item[0]

# Look up the character in the counter.

if counts[c] < 4:

new_list.append(item)



pHand[0] = new_list

Thank you. I found all the replies useful but yours the most useful because of the descriptions and indepth steps so I could understand what the code did.

Would you also happen to know how I could go about setting up a list that keeps track of the removed sets?

For example, if there were 4 a's removed, that would be one set. And the list would be:

['a']

but if there was also 4j's in addition to the a's. It would be:

['a', 'j']

And so forth....
 
K

kevin4fong

Basically, I'm trying to find out how to remove matching items from a
list. But there doesn't seem to be any information on how to go about
doing this specific function.



The documentation cannot possibly cover every single one of the infinite

number of things somebody might want to do with Python. Programming is

about figuring out how to do the things you want from the tools provided

by the language.




For example, what I want is:
let's say there is a list:
pHands[0] = ['ad', 'ac', 'as', 'ah', '7d', '8s', '9d', 'td', 'js', 'jd']
So up there, my list, which is named pHands[0] has ten items in it.



Ten items? I wouldn't have known that if you didn't say so! *wink*



But seriously... you don't need to repeat obvious things like that. We

can count as well as you can.



But more importantly, it is irrelevant. Is "ten items" important to this

problem? No. What if there were nine, or thirty five, or seven? Would the

problem of "removing matching items" change? No, the problem remains the

same regardless of how many items there are.




I'm trying to make a function where a search is initiated into the list
and any matching items with a first matching number/letter reaching four
are removed



In general, rather than removing items from a list, it is faster and

safer (less error-prone) to create a new list with the items not removed.

But either way, when trying to program, start by thinking about how *you*

would do this task by hand:



1) I would start by counting how many items start with each initial

letter: in your example I would count those starting with 'a' (4),

'7' (1), and so on.



2) Then go through those initial letters, and pick out the ones equal to

4 (or should that be "four or more"?). In this case, only 'a' is 4 or

more, but there could be multiple examples, say, 4 'a's and 6 'b's.



3) Then, either delete those items from the original list, *or* make a

new list with the remaining items. Making a new list is usually better.



Now start turning each step into Python code.



Step 1:



Iterate over each item, grab the first character of that item, and add

one to a counter.



counts = {} # Start with an empty dict.

for item in pHands[0]:

c = item[0] # Grab the first character.

if c in counts:

counts[c] += 1

else:

counts[c] = 1





This sets the counter to 1 the first time each character is seen,

otherwise increments the counter by 1. There's a ready-made tool for

doing that:



from collections import Counter

counts = Counter(item[0] for item in pHands[0])



but under the hood, it's essentially doing the same thing as I wrote

above.





Steps 2 and 3 can be done together:



new_list = []

for item in pHand[0]:

c = item[0]

# Look up the character in the counter.

if counts[c] < 4:

new_list.append(item)



pHand[0] = new_list

Thank you for the advice. It was really helpful with the descriptions and steps.

Would you also happen to know how I could set up a list that keeps track of the removed sets?

Let's say there's 4 a's taken out. The list would show:

['a']

But if there was also 4 j's in addition to the 4 a's, it would go:

['a', 'j']

and so forth.
 
K

kevin4fong

There are card games that involve more than four suits, or more than one

pack. In principle, if you draw ten cards from an unknown number of

packs, you could draw ten Aces, or even ten Aces of the same suit. Think

of playing blackjack with ten packs shuffled together.



Cripple Mr Onion, for example, uses hands of ten cards drawn from eight

suits:



http://discworld.wikia.com/wiki/Cripple_Mr_Onion



(yes, it's a real game, based on a fictional game)





The Indian Ganjifa deck uses ten "houses" (decks) of 12 cards each.



Pinochle uses the standard four Western suits, but uses two copies of

each card 9, 10, J, Q, K, A, for 48 cards in total. Sometimes people

combine two pinochle decks for larger games, so with a double deck all

ten cards could be Aces.



In the 1930s, there was a fad for playing Bridge with a fifth suit,

coloured green, called Royals, Leaves, Eagles or Rooks depending on the

manufacturer.



There are five- and six-suit versions of poker, with at least two still

commercially available: the five-suit Stardeck pack (which adds Stars),

and the six-suit Empire deck (which adds red Crowns and black Anchors).



There is an eight-suit Euchre pack that adds red Moons, black Stars, red

four-leaf Clovers and black Tears to the standard deck.


Thank you for the advice. It was really helpful with the descriptions and steps.

Would you also happen to know how I could set up a list that keeps track of the removed sets?

Let's say there's 4 a's taken out. The list would show:

['a']

But if there was also 4 j's in addition to the 4 a's, it would go:

['a', 'j']

and so forth.
 
K

kevin4fong

Basically, I'm trying to find out how to remove matching items from a list. But there doesn't seem to be any information on how to go about doing this specific function.



For example, what I want is:



let's say there is a list:



pHands[0] = ['ad', 'ac', 'as', 'ah', '7d', '8s', '9d', 'td', 'js', 'jd']



So up there, my list, which is named pHands[0] has ten items in it.



I'm trying to make a function where a search is initiated into the list and any matching items with a first matching number/letter reaching four are removed



So in the end, ad, ac, as, ah (the four a's) will all be deleted/removed from the list. I need the list to automatically detect if there are four matching first letter/numbers in the items in the list.



The remaining list will be: pHands[0] = ['7d', '8s', '9d', 'td', 'js', 'jd']


Thank you for the advice. It was really helpful with the descriptions and steps.

Would you also happen to know how I could set up a list that keeps track of the removed sets?

Let's say there's 4 a's taken out. The list would show:

['a']

But if there was also 4 j's in addition to the 4 a's, it would go:

['a', 'j']

and so forth.
 
K

kevin4fong

Thank you, Steven, for the advice. It was really helpful with the descriptions and steps.

Would you also happen to know how I could set up a list that keeps track of the removed sets?

Let's say there's 4 a's taken out. The list would show:

['a']

But if there was also 4 j's in addition to the 4 a's, it would go:

['a', 'j']

and so forth.
 
S

Steven D'Aprano

Would you also happen to know how I could go about setting up a list
that keeps track of the removed sets?

For example, if there were 4 a's removed, that would be one set. And the
list would be:

['a']

but if there was also 4j's in addition to the a's. It would be:

['a', 'j']

And so forth....


How would *you* do it in person? Start with that, then turn it into
Python code.

For example, you might count the cards first, as in my previous post,
then look at each counter. If the counter is four (or greater), add it to
a list of cards to be removed.

# counter is a dict like {'a': 4, '7': 1} as per previous post
cards_to_remove = []
for card in counter:
if counter[card] >= 4:
cards_to_remove.append(card)


Or you could do this at the same time as you build the counter. I leave
it to you to work out how to do that.

The important thing is, you have to start by asking the question, "How
would I do this task?" before you can write Python code for it.
 
D

Dave Angel

Would you also happen to know how I could set up a list that keeps track of the removed sets?

Let's see, i think that makes 5 times you've asked the same question,
counting the dups you apparently sent to the same person.

Instead of writing all these messages, could you perhaps actually write
some code? Show us that you've learned something, and that you actually
tried to get the next answer?

Frame your question around one of the following scenarios:

Here's some code I wrote, and it doesn't work because:

1) it gets an exception (show full traceback)
2) it hangs
3) it gets this answer: show actual answer
instead of what I expected: show what you expected to get

And when you post the code, paste it into your message, don't point to
some temporary website.

And if you must use googlegroups, please edit your messages to hide the
bugs in googlegarbage. Go into the message and tediously delete all the
stupid extra blank lines, because one person doing it is better than
1000 people seeing double-spaced nonsense. Many people just won't see a
message sent from googlegroups because they filter them out.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,808
Messages
2,569,686
Members
45,452
Latest member
AmberLayde

Latest Threads

Top