How to write this as a list comprehension?

P

Piet van Oostrum

Hi,

I am looking for an elegant way to write the following code as a list
comprehension:

labels = []
for then, name in mylist:
_, mn, dy, _, _, _, wd, _, _ = localtime(then)
labels.append(somefunc(mn, day, wd, name))

So mylist is a list of tuples, the first member of the tuple is a time
(as epoch offset) and I neeed to apply a function on some fields of the
localtime of it.

I could define a auxiliary function like:

def auxfunc(then, name):
_, mn, dy, _, _, _, wd, _, _ = localtime(then)
return somefunc(mn, day, wd, name)

and then use
[auxfunc(then, name) for then, name in mylist]

or even
[auxfunc(*tup) for tup in mylist]

But defining the auxfunc takes away the elegance of a list comprehension. I would like to integrate the unpacking of localtime() and calling somefunc within the list comprehension, but I don't see a simple way to do that.

somefunc(mn, day, wd, name) for _, mn, dy, _, _, _, wd, _, _ in [localtime(then)]
(i.e. using a list comprehension on a one element list to do the variable shuffling)
works but I don't find that very elegant.

labels = [somefunc(mn, day, wd, name)
for then, name in mylist
for _, mn, dy, _, _, _, wd, _, _ in [localtime(then)]]

Python misses a 'where' or 'let'-like construction as in Haskell.

Anybody has a more elegant solution?
 
D

Dan Stromberg

Hi,

I am looking for an elegant way to write the following code as a list
comprehension:

labels = []
for then, name in mylist:
_, mn, dy, _, _, _, wd, _, _ = localtime(then)
labels.append(somefunc(mn, day, wd, name))

My recomendation: Don't use a list comprehension. List comprehensions
and generator expressions are great for quick little things, but
become less readable when you have to string them over multiple
physical lines.
labels = [somefunc(mn, day, wd, name)
for then, name in mylist
for _, mn, dy, _, _, _, wd, _, _ in [localtime(then)]]
 
R

Rustom Mody

I am looking for an elegant way to write the following code as a list
comprehension:
labels = []
for then, name in mylist:
_, mn, dy, _, _, _, wd, _, _ = localtime(then)
labels.append(somefunc(mn, day, wd, name))
So mylist is a list of tuples, the first member of the tuple is a time
(as epoch offset) and I neeed to apply a function on some fields of the
localtime of it.
I could define a auxiliary function like:
def auxfunc(then, name):
_, mn, dy, _, _, _, wd, _, _ = localtime(then)
return somefunc(mn, day, wd, name)
and then use
[auxfunc(then, name) for then, name in mylist]
or even
[auxfunc(*tup) for tup in mylist]
But defining the auxfunc takes away the elegance of a list comprehension. I would like to integrate the unpacking of localtime() and calling somefunc within the list comprehension, but I don't see a simple way to do that.
somefunc(mn, day, wd, name) for _, mn, dy, _, _, _, wd, _, _ in [localtime(then)]
(i.e. using a list comprehension on a one element list to do the variable shuffling)
works but I don't find that very elegant.
labels = [somefunc(mn, day, wd, name)
for then, name in mylist
for _, mn, dy, _, _, _, wd, _, _ in [localtime(then)]]
Python misses a 'where' or 'let'-like construction as in Haskell.

+1
Yes Ive often been bitten by the lack of a 'comprehension-let'

Something like this is possible??


[somefunc(mn,day,wd,name) for (_, mn,dy,_,_,_,wd,_,_), name) in [localtime(then), name for then, name in mylist]]

Some debugging of the structure will be necessary (if at all possible)
I dont have your functions so cant do it
 
P

Peter Otten

Piet said:
Hi,

I am looking for an elegant way to write the following code as a list
comprehension:

labels = []
for then, name in mylist:
_, mn, dy, _, _, _, wd, _, _ = localtime(then)
labels.append(somefunc(mn, day, wd, name))

So mylist is a list of tuples, the first member of the tuple is a time
(as epoch offset) and I neeed to apply a function on some fields of the
localtime of it.

I could define a auxiliary function like:

def auxfunc(then, name):
_, mn, dy, _, _, _, wd, _, _ = localtime(then)
return somefunc(mn, day, wd, name)

and then use
[auxfunc(then, name) for then, name in mylist]

or even
[auxfunc(*tup) for tup in mylist]

But defining the auxfunc takes away the elegance of a list comprehension.
I would like to integrate the unpacking of localtime() and calling
somefunc within the list comprehension, but I don't see a simple way to do
that.

somefunc(mn, day, wd, name) for _, mn, dy, _, _, _, wd, _, _ in
[localtime(then)] (i.e. using a list comprehension on a one element list
to do the variable shuffling) works but I don't find that very elegant.

labels = [somefunc(mn, day, wd, name)
for then, name in mylist
for _, mn, dy, _, _, _, wd, _, _ in [localtime(then)]]

Python misses a 'where' or 'let'-like construction as in Haskell.

Anybody has a more elegant solution?

Options I can think of:

You could do it in two steps...

time_name_pairs = ((localtime(then), name) for then, name in mylist)
labels = [somefunc(t.tm_mon, t.tm_mday, t.tm_wday, name)
for t, name in time_name_pairs]

....or you could inline the helper function...

mon_mday_wday = operator.attrgetter("tm_mon", "tm_day", "tm_wday")
labels = [somefunc(*mon_mday_wday(localtime(then)), name=name)
for then, name in mylist]

-- but both seem less readable than the classical for-loop.

What would a list-comp with `let` or `where` look like? Would it win the
beauty contest against the loop?
 
P

Piet van Oostrum

Rustom Mody said:
+1
Yes Ive often been bitten by the lack of a 'comprehension-let'

If it used only in a comprehension as in my example you can write instead of 'where vars = expr':
for vars in [expr], unnecessarily construction a one element list.
If there would be a syntax like:
for vars = expr
this could be avoided.
Something like this is possible??


[somefunc(mn,day,wd,name) for (_, mn,dy,_,_,_,wd,_,_), name) in
[localtime(then), name for then, name in mylist]]
It works modulo some corrections in the parentheses:

[somefunc(mn,day,wd,name) for (_, mn,dy,_,_,_,wd,_,_), name in
[(localtime(then), name) for then, name in mylist]]
but I find that hardly more elegant.
 
M

Matěj Cepl

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

But defining the auxfunc takes away the elegance of a list
comprehension.

Au contraire! Remember, that brevity is the sister of talent.

I would definitively vote for

labels = [make_label(then, name) for then, name in mylist]

(always use descriptive names of functions and variables;
auxfunc is a short way to the hell)

Beauty of the list comprehensions is that they show nicely what
list is being processed, how it is filtered (if at all), and
what we do with each element of the generated list. Anything you
add to this simplicity is wrong. Whenever you start to feel you
are missing some methods how to stuff more commands into
a comprehension (or for example multiple embedded ones), you
should start new function.

The same rule applies here as with any other lambda function
(because these are in fact lambda functions): the best way how
to write lambda is to write algorithm somewhere on the side,
describe what this function does in one word, then add `def` in
front of that name, and use so created named function instead.

Best,

Matěj

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.22 (GNU/Linux)

iD8DBQFS2l4X4J/vJdlkhKwRAjEgAJ4n1OuANYlVFzlgBZ0f1uMhO/t36gCfdFjE
VmYDJ+F7aN0khzvlY50i0iA=
=Trcc
-----END PGP SIGNATURE-----
 
A

Alain Ketterlin

[...]
I could define a auxiliary function like:

def auxfunc(then, name):
_, mn, dy, _, _, _, wd, _, _ = localtime(then)
return somefunc(mn, day, wd, name)

and then use
[auxfunc(then, name) for then, name in mylist]
[...]

labels = [somefunc(mn, day, wd, name)
for then, name in mylist
for _, mn, dy, _, _, _, wd, _, _ in [localtime(then)]]

Python misses a 'where' or 'let'-like construction as in Haskell.

"let x = v in e" really is (lambda x:e)(v)

In your case:

[ (lambda na,ti : somefunc(ti[1],ti[2],ti[6],na))(name,localtime(then))
for then,name in mylist ]

Warning: absolutely untested (not even syntax-checked).

You may also use *localtime(...) and keep underscores.

-- Alain.
 
R

Rustom Mody

Options I can think of:
You could do it in two steps...
time_name_pairs = ((localtime(then), name) for then, name in mylist)
labels = [somefunc(t.tm_mon, t.tm_mday, t.tm_wday, name)
for t, name in time_name_pairs]
...or you could inline the helper function...
mon_mday_wday = operator.attrgetter("tm_mon", "tm_day", "tm_wday")
labels = [somefunc(*mon_mday_wday(localtime(then)), name=name)
for then, name in mylist]
-- but both seem less readable than the classical for-loop.
What would a list-comp with `let` or `where` look like? Would it win the
beauty contest against the loop?

For me this is neat

[somefunc(mn,day,wd,name) for (then, name) in mylist let (_,mn,dy,_,_,_,wd,_,_) = localtime(then)]

Others may not find it so!

See it across > 1 line (as I guess it will come after being posted!) and its not so neat.
 
J

Jussi Piitulainen

Rustom said:
What would a list-comp with `let` or `where` look like? Would it
win the beauty contest against the loop?

For me this is neat

[somefunc(mn,day,wd,name) for (then, name) in mylist let (_,mn,dy,_,_,_,wd,_,_) = localtime(then)]

Others may not find it so!

See it across > 1 line (as I guess it will come after being posted!)
and its not so neat.

I would write that on three lines anyway, properly indented:

[ somefunc(mn,day,wd,name)
for (then, name) in mylist
let (_,mn,dy,_,_,_,wd,_,_) = localtime(then) ]

It could be made to use existing keywords:

[ somefunc(mn,day,wd,name)
for (then, name) in mylist
with localtime(then) as (_,mn,dy,_,_,_,wd,_,_) ]
 
J

John Allsup

Hi,

I'd agree with the advice that it's not the best idea: readability sucks
here, but consider the following:


import time

def somefunc(a,b,c,d): # dummy function
return "{} - {} - {} : {}".format(a,b,c,d)
l = [(time.time(),"name {}".format(n)) for n in range(100)] # dummy data

# the line in question
labels = [somefunc(*(lambda t,n:
(t.tm_mon,t.tm_mday,t.tm_wday,n))(time.localtime(x[0]),x[1])) for x in l]


print(labels) # just to see the result


If you find that hard to decipher, the consider the maintainability of
code you write that uses such comprehensions. You need to include
comments that explain what this does, and it is easier to write a
longhand version using .append() and variable assignments. I presume
performance won't be an issue determining the right approach, since then
you'd be using C or C++.

John

Hi,

I am looking for an elegant way to write the following code as a list
comprehension:

labels = []
for then, name in mylist:
_, mn, dy, _, _, _, wd, _, _ = localtime(then)
labels.append(somefunc(mn, day, wd, name))

My recomendation: Don't use a list comprehension. List comprehensions
and generator expressions are great for quick little things, but
become less readable when you have to string them over multiple
physical lines.
labels = [somefunc(mn, day, wd, name)
for then, name in mylist
for _, mn, dy, _, _, _, wd, _, _ in [localtime(then)]]
 

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,770
Messages
2,569,583
Members
45,073
Latest member
DarinCeden

Latest Threads

Top