list comprehention

P

Patrick Maupin

Duncan Booth showed how to solve a problem posed by Mathijs. This is
very similar to Duncan's solution, except I (ab)use setdefault on a
regular basis...
.... res = {}
.... for item in t:
.... res.setdefault(item,[0])[0] += 1
.... return res
....
ref = [2,2,4,1,1]
lst = [2,2,5,2,4]
oref = occurrences(ref)
sum(min(v[0],oref.get(k,[0])[0]) for (k,v) in occurrences(lst).iteritems()) 3

Actually, this brings up an interesting point:
SyntaxError: can't assign to function call

I understand why this doesn't work, but it would sure be nice if it
did. I think somebody was mentioning "mutable ints" at one point,
which is basically what I abuse [0] to provide. If I were doing a lot
of this in one place, I would code a mutable integer class, and then
the rest of the code would get simpler.

Regards,
Pat
 
B

Bryan Olson

Bryan said:
Duncan said:
Here's the way I would do it:
def occurrences(it):


res = {}
for item in it:
if item in res:
res[item] += 1
else:
res[item] = 1
return res


I slightly prefer:

def occurrences(it):
res = {}
res[item] = res.get(item, 0) + 1
return res

Arg! In illustrating a trivial point, I dropped something essential.
This version has almost three minutes of testing behind it:

def occurrences(it):
res = {}
for item in it:
res[item] = res.get(item, 0) + 1
return res
 
M

Morten Vold

len([ref.pop(ref.index(x)) for x in lis if x in ref])
This is the type of solution I was hoping to see: one-liners, with no
use of local variables. As Tim Chase already wrote, it has only one
less elegant side: it alters the original ref list.

Thanks for your suggestion.

May I suggest another one-liner:

len(set(ref).intersection(lis))

I have no idea how this scales/performs compared to the other
suggestions you've received, but I find it immediately comprehensible.


-- Morten
 
P

Peter Otten

[Mathijs]
Example2:
ref=[2, 2, 4, 1, 1]
list=[2, 2, 5, 2, 4]
solution: 3 (note that only the first two 2's count, the third 2 in the
list should not be counted)

[Morten Vold]
May I suggest another one-liner:

len(set(ref).intersection(lis))

I have no idea how this scales/performs compared to the other
suggestions you've received, but I find it immediately comprehensible.
len(set([2, 2, 4, 1, 1]).intersection([2, 2, 5, 2, 4]))
2

Close, but no cigar.

Peter
 
D

Duncan Booth

Patrick said:
... res = {}
... for item in t:
... res.setdefault(item,[0])[0] += 1
... return res
....
I think somebody was mentioning "mutable ints" at one point,
which is basically what I abuse [0] to provide. If I were doing a lot
of this in one place, I would code a mutable integer class, and then
the rest of the code would get simpler.

Or you could use the facilities built in to Python: use the get method as
Bryan did, and the code gets simpler without using mutable integers.

I prefer writing an 'if' statement here, Bryan prefers 'get', that's just a
choice of style. But 'setdefault' here, that has no style.
 
P

Patrick Maupin

Duncan said:
I prefer writing an 'if' statement here, Bryan prefers 'get', that's just a
choice of style. But 'setdefault' here, that has no style.

Well, I'm often told I have no style, and I _did_ admit that it's an
abuse of setdefault. However, I often use setdefault to populate
nested dictionaries, or dictionaries of sets or lists, e.g.:

for x, y in somebiglist:
bigdict.setdefault(x,set()).add(y) # Strips duplicates


for x, y in somebiglist:
bigdict.setdefault(x,[]).append(y) # Preserves duplicates

To my mind, this latter is so much cleaner and clearer than any of the
alternatives that it just isn't funny:

for x, y in somebiglist:
if x in bigdict:
bigdict[x].append(y)
else:
bigdict[x] = [y]

for x, y in somebiglist:
if x not in bigdict:
bigdict[x] = []
bigdict[x].append(y)

for x, y in somebiglist:
try:
bigdict[x].append(y)
except KeyError:
bigdict[x] = [y]

etc.

Since I use setdefault in this manner quite often, I am very
comfortable with it. On a single line I know what I am creating (list,
dict, set, etc.), what the default value is, and how it is being
modified.

Because I am NOT a believer in the Perl idiom of TMTOWTDI, and because,
TO ME, setdefault screams "This line is creating and subsequently
modifying a dictionary entry", setdefault is absolutely my first choice
for this particular task.

Having said that, my enthusiasm for setdefault (for the given problem!)
IS tempered somewhat by having to abuse a list as a mutable integer.
That is the only reason that I concede that my solution is an abuse of
setdefault, but the setdefault idiom is (to me) so clear and compelling
that I view it as a toss-up whether to use a single line setdefault or
an if/else in this case.

And, as I mentioned earlier, if I had to do this same thing LOTS of
times in a program, I most likely would code a class (perhaps not as
fancy as a true mutable int, but certainly something with an increment
method), because, IMO, it would be a lot cleaner (hmmm, maybe there's
no style points in that) than tons and tons of if/else statements.

Regards,
Pat
 
D

Duncan Booth

Patrick said:
Duncan said:
I prefer writing an 'if' statement here, Bryan prefers 'get', that's
just a choice of style. But 'setdefault' here, that has no style.

Well, I'm often told I have no style, and I _did_ admit that it's an
abuse of setdefault. However, I often use setdefault to populate
nested dictionaries, or dictionaries of sets or lists, e.g.:

for x, y in somebiglist:
bigdict.setdefault(x,set()).add(y) # Strips duplicates


for x, y in somebiglist:
bigdict.setdefault(x,[]).append(y) # Preserves duplicates

To my mind, this latter is so much cleaner and clearer than any of the
alternatives that it just isn't funny:

Yes, but storing a mutable is a not unreasonable use of setdefault. What I
objected to was storing an immutable just to overwrite it immediately.

Also, while I agree it is shorter, I'm not convinced that it is much
cleaner, and it is likely to be slower if there are a lot of duplicates,
possibly a lot slower if the mutable object has much overhead on its
construction.
 
P

Paddy

Umm,
My answer is not correct, but for a different reason; it seems you need
the length of my
previous answer, thus:

PythonWin 2.4 (#60, Feb 9 2005, 19:03:27) [MSC v.1310 32 bit (Intel)]
on win32.
Portions Copyright 1994-2004 Mark Hammond ([email protected]) -
see 'Help/About PythonWin' for further copyright information.
ref = [3, 3, 1, 1, 3]
lst=[5, 1, 4, 5, 3]
answer = len([ val for val in set(ref) for x in range(min(lst.count(val), ref.count(val)))])
answer 2

- Paddy.
 
M

Mathijs

23 jan 2006 ta (Steven D'Aprano) shuo le:
Because you like unreadable, incomprehensible, unmaintainable code?

For practical use: no! But I'm just learning python and to understand
sets/lists/dicts and it's functions, this seemed like good practise:) and
besides that: it's fun! A solution with local vaiables, if-statemenst and a
for loop wouldn't be much different from what I know with my current
programming skills.

Yeah, yeah, I know, but I felt a response was on its place. :)
 

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

Forum statistics

Threads
474,282
Messages
2,571,404
Members
48,096
Latest member
Kenkian2628

Latest Threads

Top