Is there a better way to chose a slice of a list?

P

pruebauno

This works, but it seems like there should be a better way.

--------------
week = ['sun','mon','tue','wed','thu','fri','sat']
for day in week[week.index('tue'):week.index('fri')]:
   print day
---------------

Depending on the context this style might help:
week = ['sun','mon','tue','wed','thu','fri','sat']
tue_fri = slice(week.index('tue'), week.index('fri'))
for day in week[tue_fri]:
print day

But I don't really see it as an improvement unless you are using those
intervals repeatedly.
 
J

John Yeung

This works, but it seems like there should be a better way.

--------------
week = ['sun','mon','tue','wed','thu','fri','sat']
for day in week[week.index('tue'):week.index('fri')]:
   print day
---------------

I think you should provide much more information, primarily why you
want to do this. What is the larger goal you are trying to achieve?

In the absence of further information, it seems to me that you are
trying to create an enumerated type. For various ideas to achieve
this simply, depending on your purpose, see

http://norvig.com/python-iaq.html

If you want a more thorough treatment, maybe try this package:

http://pypi.python.org/pypi/enum/

There may be other recipes and packages; you can Google for them using
keywords "python enum" or similar.

John
 
W

walterbyrd

This works, but it seems like there should be a better way.
--------------
week = ['sun','mon','tue','wed','thu','fri','sat']
for day in week[week.index('tue'):week.index('fri')]:
   print day
---------------

I think you should provide much more information, primarily why you
want to do this.  What is the larger goal you are trying to achieve?

I am just looking for a less verbose, more elegant, way to print a
slice of a list. What is hard to understand about that? I am not sure
how enumerated types help.
 
T

Terry Reedy

walterbyrd said:
This works, but it seems like there should be a better way.
--------------
week = ['sun','mon','tue','wed','thu','fri','sat']
for day in week[week.index('tue'):week.index('fri')]:
print day
---------------
I think you should provide much more information, primarily why you
want to do this. What is the larger goal you are trying to achieve?

I am just looking for a less verbose, more elegant, way to print a
slice of a list.

week[2:5] # ;-)

If you want the interpreter to turn non-ints into ints for you, you will
have to give it some sort of function or mapping to use.

dayint = {day:i for i,day in enumeratr(week)} # works in Py3 at least
week[dayint['tue']:dayint['fri']]

# or, untested, basing attrodic on memory of posted code

class attrodic(): #py3
def __init__(self, dic):
self.__dict__.update(dic)

di = attrodic(week)
week[di.tue:di.fri]

Most elegant, and most setup work ;-).

Terry Jan Reedy
 
R

Rhodri James

This works, but it seems like there should be a better way.
--------------
week = ['sun','mon','tue','wed','thu','fri','sat']
for day in week[week.index('tue'):week.index('fri')]:
   print day
---------------

I think you should provide much more information, primarily why you
want to do this.  What is the larger goal you are trying to achieve?

I am just looking for a less verbose, more elegant, way to print a
slice of a list. What is hard to understand about that? I am not sure
how enumerated types help.

This is verbose and inelegant because of the way you're storing and
using the data, hence (I presume) John's question. The more elegant
approach is not to try to index a list with strings, but to keep you
"day" data in numeric form and use that to slice with, and for that
enums will greatly help you keep things clear. However, whether that's
worth doing or not depends on the bigger picture, and you haven't
told us anything that would help us figure that out.
 
J

John Machin

I am just looking for a less verbose, more elegant, way to print a
slice of a list. What is hard to understand about that?

Ummm two things, (1) You didn't say that was what you wanted (2) It's
a nonsense anyway:

Your original statement "choose a slice of alist": answer = alist
[lo:hi]

Your current statement "print a slice of a list" (one element per line
as per your example): can not be done much less verbosely and more
elegantly than:
for x in alist[lo:hi]:
print x

Your real problem appears to be the horrid method of deriving lo and
hi.

You gave ONE example without stating anything more precise than that
it was an example of a slice of a list [which was obvious anyway] and
didn't specify in what sense of "better" you wanted a better way. So
people have to guess what you really want.

Guessing that the 'tue' and 'fri' in your one example will always be
constants, here are two options:

E.g. given
week = ['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat']

Option (1):
SUN, MON, TUE, WED, THU, FRI, SAT = range(7)
for day in week[TUE:FRI]:
print day

Option (2):
for day in week[2:5]:
print day

HTH,
John
 
S

Steven D'Aprano

This works, but it seems like there should be a better way.
--------------
week = ['sun','mon','tue','wed','thu','fri','sat'] for day in
week[week.index('tue'):week.index('fri')]:
   print day
---------------

I think you should provide much more information, primarily why you
want to do this.  What is the larger goal you are trying to achieve?

I am just looking for a less verbose, more elegant, way to print a slice
of a list. What is hard to understand about that? I am not sure how
enumerated types help.

Printing a slice of a list is about as concise and elegant as possible:

print alist[slice_obj]

or

print alist[start:end:step]

But that's not what the example in your first post suggests. Your example
suggests you have *two* problems:

(1) Given a slice, how to print each item in the slice _individually_.

The answer to that is

for x in aslice:
print x

Pretty concise and elegant.



(2) Given an arbitrary starting and ending _item_ rather than _position_,
how to concisely and elegantly generate a slice.

There are many answers, depending on _why_ you want to do this. One
possible answer is to write a function to do it:

def print_slice(alist, start_item, end_item):
start_pos = alist.index(start_item)
end_pos = alist.index(end_item)
for x in alist[start_pos:end_pos]:
print x

Now print_slice(week, 'tue', 'fri') is pretty concise and elegant.

Another answer is: Don't do that, do something else. If you have an
enumerated type, then you could (in principle) do this:

week = enumerated('mon tue wed thu fri sat sun')
for x in week.tue-week.fri:
print x


depending on the enumerated type itself naturally.
 
P

Piet van Oostrum

walterbyrd said:
w> I am just looking for a less verbose, more elegant, way to print a
w> slice of a list. What is hard to understand about that? I am not sure
w> how enumerated types help.

You didn't say that in the OP.

But you can extend the list type to accept slices with strings in them.
The language spec says they should be ints but apparently this is not
enforced. Of course this makes it vulnerable for future misbehaviour.

class KeyList(list):
def __getitem__(self, indx):
if isinstance(indx, slice):
start = indx.start
stop = indx.stop
# add support for step if you want
if not isinstance(start, int):
start = self.index(start)
if not isinstance(stop, int):
stop = self.index(stop)
return list.__getitem__(self, slice(start,stop))
return list.__getitem__(self, indx)

week = KeyList(['sun','mon','tue','wed','thu','fri','sat'])
for day in week['tue':'fri']:
print day

tue
wed
thu

Note that 'fri' is not included according to standard Python conventions
about the end of a slice. Change the code if you are not happy with it
and you don't mind getting inconsistent semantics.
 
W

walterbyrd

That's just the same micro-goal re-stated. What is your larger problem
of which this is a part? Perhaps a better approach can be suggested when
that context is known.

I am processing a huge spreadsheet which I have converted to a csv
format. Each row will be a wiki page with several sub-headings. The
spreadsheet contains information about servers. Wiki sub-headings may
include: 'hardware', 'software', 'users', 'network swith settings'.
'Hardware' may include the spreadsheet columns: 'memory', 'cpu', and
so on. So the first six columns in the spreadsheet may go under
'hardware' the next six under 'software' and so on.

I have already created the wiki pages, using a method similar to what
I first posted. But, it seems like there should be a better way to to
do it. So, for future reference, I was just wondering.
 
R

Rhodri James

I am processing a huge spreadsheet which I have converted to a csv
format. Each row will be a wiki page with several sub-headings. The
spreadsheet contains information about servers. Wiki sub-headings may
include: 'hardware', 'software', 'users', 'network swith settings'.
'Hardware' may include the spreadsheet columns: 'memory', 'cpu', and
so on. So the first six columns in the spreadsheet may go under
'hardware' the next six under 'software' and so on.

I have already created the wiki pages, using a method similar to what
I first posted. But, it seems like there should be a better way to to
do it. So, for future reference, I was just wondering.

Given that you're already making presumptions about the nature of your
data, named constants or enums are the most concise thing to use together
with a quick check of the column header row to make sure that the
constants really do refer to the right columns.

If you want something a little more bullet-proof, create a dictionary
mapping the column headers (as read in) to column numbers and use that
to generate the slice limits. Since that still relies on the column
headers being what you expect them to be, and at least partially in the
order you expect them to be, it's probably not enough of a win to bother
with.

Trying to slice a list by value is never going to look pretty because
lists aren't designed to be indexed by value. Worse, if you were
doing this a lot (as you imply) then it's going to be horribly
inefficient, since you're doing an extra two (or more) O(n) searches
for every row.
 

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,744
Messages
2,569,484
Members
44,904
Latest member
HealthyVisionsCBDPrice

Latest Threads

Top