Do this as a list comprehension?

T

Terry Reedy

| > zip(range(9,2000000000), iterable)
|
| Oh, dear. You didn't actually try this, did you?

Works fine in Py3, which is what I use now.
 
L

Lie

That's a bad habit to teach a newbie, isn't it?


The issue I'm stressing is HOW they got to be
the same size. If I was teaching programming
and the OP turned in that example, I would mark
him down. Not because he got the answer wrong.
Not because he used zip. Not because he failed
to use enumerate or itertools. But because he
hardcoded the array bounds and THAT'S the lesson
the OP should take away from this.

Mark him down? Rather blind attack on the approach. If I have a
variable coord that contains (x, y, z) and I hardcoded their meanings
and bounds, you're still marking me down for the possibility of adding
a fourth dimension? While I'm aware that I won't ever be concerned by
the fourth, fifth, ... dimensions ever in my life.

In some usage, hardcoding has no harm and in fact might be useful.

If I have a data that contains 8 sections, and I know that since this
is a low level protocol, it's not going to grow legs and arms. It's
natural to use a list/tuple and hardcode the datas length.
Based on the variable names, it seemed reasonable that
there would always be a 1-to-1 correspondence between
elements of each list. �

Yes, reasonable at the time. But this is Python,
not C. Lists can change size under program control,
a feature that's extremely useful. But there's a
price for that usefulness. Practices that made
sense in C (define a constant to set array bounds)
aren't transportable over to systems that simply
don't have the restrictions that require those
practices.
However, if you do
score_costs = [(base_scores, score_costs) for i in range (min (len
(base_scores), len (score_costs))]

then you get exactly what you would get using zip. �

And if the iterables change size dynamically, you
could get either a crash due to index out of range
or else silently a wrong answer.
That's one heck of a
long line, though, hence my earlier comment:

I have no problem telling the OP this method.
But I think you should warn him about potential
problems.

Surely you didn't intend to leave him to twist
in the wind so that he learns a thing or two
when his programs crash?


That's the best way to learn: "making mistakes".
You don't learn anything if you never make mistakes.
That's all I'm suggesting. Along with pointing out
that enumerate or itertools can do this for him.

I think it's up to the OP, not you, to decide whether the use of bare
zip is enough and whether data truncation might or might not be a
problem. It seems that since he has used zip in his original post, he
thought it fits his situation best, perhaps its truncation behavior is
something he wanted to exploit in the first place.
 
L

Lie

Ok, sorry I thought otherwise.


Yes, because you're controlling the source code.
But since lists are mutable, source code literals
don't always control the length of the list.

Since when source code literals ever control the length of a list?
What controls the length of the list is the semantic meaning of the
list, in some cases it just makes no sense that the list would ever
have different length.

(snip)
 
M

Mensanator

| > zip(range(9,2000000000), iterable)
|
| Oh, dear. You didn't actually try this, did you?

Works fine in Py3, which is what I use now.

You really ARE cruel to the newbies, aren't you?

Don't you think it would have been appropriate
to attach a large red label: WARNING! PY3!
 
M

Mensanator

Since when source code literals ever control the length of a list?

Isn't score_costs = [0, 1, 1, 1, 1, 1, 1, 2, 2, 3, 3]
considered a literal?
What controls the length of the list is the semantic meaning of the
list,

Wha do you mean by that? The list contains 11 objects.
How could the length be any different?
in some cases it just makes no sense that the list would ever
have different length.

And in such case there won't be any problem, will there?

Is that a good habit to teach a newbie? To write
code that only works for special cases?
 
J

John Salerno

Mensanator said:
You really ARE cruel to the newbies, aren't you?

Don't you think it would have been appropriate
to attach a large red label: WARNING! PY3!

Heh heh, don't worry. Every time I see a range function, I immediately
think "creates a list". Not sure how I got into that habit, but it
happens every time! :)
 
M

Mensanator

Heh heh, don't worry. Every time I see a range function, I immediately
think "creates a list". Not sure how I got into that habit, but it
happens every time! :)

You probably got into that habit because that's
what it does in 2.x, create a list. Now, if
you're expecting that to happen you'll in for
a surprise when you switch to Py3, won't you?
 
R

Ricardo Aráoz

Mensanator said:
Is it possible to write a list comprehension for this so as to produce a
list of two-item tuples?
base_scores = range(8, 19)
score_costs = [0, 1, 1, 1, 1, 1, 1, 2, 2, 3, 3] print zip(base_scores,
score_costs)
score_costs = [(base_scores, score_costs) for i in range (len
(base_scores))]


What happens if your iterables aren't the same length?
But, I'd rather just use zip. :)

And with zip() you won't get an error, but it won't be correct,
either.


Wouldn't it be nice to have leftZip(), rightZip(), and fullZip() for
when the lists have different lengths? The final tuples for a leftZip
could be in the form (value, ) and for right zip (, value) (though I
think this last tuple is not allowed in python's syntax, we might define
a "Null" or "Empty" name to act as a place holder in the resulting tuples).
 
J

Jason Scheirer

Mensanator said:
On Thu, 05 Jun 2008 23:42:07 -0400, John Salerno wrote:
Is it possible to write a list comprehension for this so as to produce a
list of two-item tuples?
base_scores = range(8, 19)
score_costs = [0, 1, 1, 1, 1, 1, 1, 2, 2, 3, 3] print zip(base_scores,
score_costs)
score_costs = [(base_scores, score_costs) for i in range (len
(base_scores))]

What happens if your iterables aren't the same length?
And with zip() you won't get an error, but it won't be correct,
either.

Wouldn't it be nice to have leftZip(), rightZip(), and fullZip() for
when the lists have different lengths? The final tuples for a leftZip
could be in the form (value, ) and for right zip (, value) (though I
think this last tuple is not allowed in python's syntax, we might define
a "Null" or "Empty" name to act as a place holder in the resulting tuples)..


You can go

zip(xrange(9, 10000000000L), [0, 1, 1, 1, 1, 1, 1, 2, 2, 3, 3])

since xrange DOES NOT return a list but a constant-memory iterable.

Also, there is itertools for adding default values after you fall off
the end of a list.
import itertools
zip(xrange(100), itertools.chain([0, 1, 1, 1, 1, 1, 1, 2, 2, 3, 3], itertools.cycle([None])))

Whose output is:

[(0, 0), (1, 1), (2, 1), (3, 1), (4, 1), (5, 1), (6, 1), (7, 2), (8,
2), (9, 3), (10, 3), (11, None), (12, None), (13, None), (14, None),
(15, None), (16, None), (17, None), (18, None), (19, None), (20,
None), (21, None), (22, None), (23, None), (24, None), (25, None),
(26, None), (27, None), (28, None), (29, None), (30, None), (31,
None), (32, None), (33, None), (34, None), (35, None), (36, None),
(37, None), (38, None), (39, None), (40, None), (41, None), (42,
None), (43, None), (44, None), (45, None), (46, None), (47, None),
(48, None), (49, None), (50, None), (51, None), (52, None), (53,
None), (54, None), (55, None), (56, None), (57, None), (58, None),
(59, None), (60, None), (61, None), (62, None), (63, None), (64,
None), (65, None), (66, None), (67, None), (68, None), (69, None),
(70, None), (71, None), (72, None), (73, None), (74, None), (75,
None), (76, None), (77, None), (78, None), (79, None), (80, None),
(81, None), (82, None), (83, None), (84, None), (85, None), (86,
None), (87, None), (88, None), (89, None), (90, None), (91, None),
(92, None), (93, None), (94, None), (95, None), (96, None), (97,
None), (98, None), (99, None)]
 
J

John Salerno

Mensanator wrote:
Heh heh, don't worry. Every time I see a range function, I immediately
think "creates a list". Not sure how I got into that habit, but it
happens every time! :)

You probably got into that habit because that's
what it does in 2.x, create a list. Now, if
you're expecting that to happen you'll in for
a surprise when you switch to Py3, won't you?

Nah, I know about the change.It might be a slight adjustment at first, but
probably a good one.
 
L

Lie

Since when source code literals ever control the length of a list?

Isn't score_costs = [0, 1, 1, 1, 1, 1, 1, 2, 2, 3, 3]
considered a literal?

Yep, but it's not the sole controller of the length of a list. There
are other things that might control the length of the list like del,
append, etc.
Wha do you mean by that? The list contains 11 objects.
How could the length be any different?

What I meant is in some cases (not all) the list might semantically be
nonsense if it is of different length (i.e. it have fixed length).
And in such case there won't be any problem, will there?

Is that a good habit to teach a newbie? To write
code that only works for special cases?

I think it is up to the programmer to decide whether special case is
enough or a general case is necessary.
 
M

Mensanator

Isn't score_costs = [0, 1, 1, 1, 1, 1, 1, 2, 2, 3, 3]
considered a literal?

Yep, but it's not the sole controller of the length of a list. There
are other things that might control the length of the list like del,
append, etc.

I believe I just said that. Perhaps I should have said
at the instant it's created, the length is determined
by the literal.

Remember,

score_costs = [0, 1, 1, 1, 1, 1, 1, 2, 2, 3, 3]

is preceeded by range(11), so of course AT THAT INSTANT,
the lengths match. But, as you say, there's no guarantee
that the list lengths will remain unchanged.

And that's why I'm saying it isn't necessarily a good idea
to assume that. For the way it's used, the zip function
IS assuming that.
What I meant is in some cases (not all) the list might semantically be
nonsense if it is of different length (i.e. it have fixed length).

Sure, but remember, the OP was asking how to do this in a
list comprehension where he doesn't have the option of
iterating through both lists like he does with zip.

When I mentioned that could be solved by enumerate, I said
it simultaneously guaratees that the index numbers automatically
end up the same length as the target list and avoids the
hypothetical case where the list lengths somehow don't match.

Of course nothing can be done if the actual list length is
semantically nonsense and you actually might need to exploit
the truncating of the list to a fixed range. But there are
many cases where you DON'T want that to happen (if you deposit
5 checks at the bank, you certainly want credit for ALL of them,
not just some idiot's notion that only 4 can be deposited in
a single transaction.)
I think it is up to the programmer to decide whether special case is
enough or a general case is necessary.

Yes, he can certainly decide. Provided he knows what all the
options are. There's no way to tell if the OP understands
what the options are. I say it's always better to supply too
much information than not enough. Assume the reader is clever
enough to seperate the wheat from the chaff. If it turns out
he's not, then I at least _I_ will be blameless.
 

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,763
Messages
2,569,562
Members
45,038
Latest member
OrderProperKetocapsules

Latest Threads

Top