slicing return iter?

S

StarWing

hello everyone, I'm new here :)

sometimes I want to iterate a part of a sequence. but don't want to
copy it. i.e.

a = list(...)
# now a is a list, and a[:] is another list, and so a[m:n]
# now we do something with the 0~len(a)-3 elements of a
for val in a[:-2]:
#do something....

but, this will cause a copy on a, has some convenience way to get a
iter to iterate on a part of list?

i made this:
class iterslice:
def __init__(self, list):
self.list = list

def __len__(self):
return len(self.list)

def __getitem__(self, slice):
import itertools
listlen = len(self.list)
range = (((slice.start + listlen) % listlen) if slice.start
else 0,
((slice.stop + listlen) % listlen) if slice.stop else
listlen,
slice.step)
return itertools.islice(self.list, *range)


a = [1,2,3,4]
for i in iterslice(a)[:-1:2]:
print i


my question is:
- are there any *Standard* way to do this? (a buit-in function? a
module?)
- are there any better implements?

thanks for attention :)
 
A

Arnaud Delobelle

hello everyone, I'm new here :)

sometimes I want to iterate a part of a sequence. but don't want to
copy it. i.e.

a = list(...)
# now a is a list, and a[:] is another list, and so a[m:n]
# now we do something with the 0~len(a)-3 elements of a
for val in a[:-2]:
    #do something....

but, this will cause a copy on a, has some convenience way to get a
iter to iterate on a part of list?

i made this:
class iterslice:
    def __init__(self, list):
        self.list = list

    def __len__(self):
        return len(self.list)

    def __getitem__(self, slice):
        import itertools
        listlen = len(self.list)
        range = (((slice.start + listlen) % listlen) if slice.start
else 0,
                ((slice.stop + listlen) % listlen) if slice.stop else
listlen,
                slice.step)
        return itertools.islice(self.list, *range)

a = [1,2,3,4]
for i in iterslice(a)[:-1:2]:
    print i

my question is:
  - are there any *Standard* way to do this? (a buit-in function? a
module?)
  - are there any better implements?

thanks for attention :)

Check the itertools module.

HTH
 
S

StarWing

hello everyone, I'm new here :)
sometimes I want to iterate a part of a sequence. but don't want to
copy it. i.e.
a = list(...)
# now a is a list, and a[:] is another list, and so a[m:n]
# now we do something with the 0~len(a)-3 elements of a
for val in a[:-2]:
#do something....
but, this will cause a copy on a, has some convenience way to get a
iter to iterate on a part of list?
i made this:
class iterslice:
def __init__(self, list):
self.list = list
def __len__(self):
return len(self.list)
def __getitem__(self, slice):
import itertools
listlen = len(self.list)
range = (((slice.start + listlen) % listlen) if slice.start
else 0,
((slice.stop + listlen) % listlen) if slice.stop else
listlen,
slice.step)
return itertools.islice(self.list, *range)
a = [1,2,3,4]
for i in iterslice(a)[:-1:2]:
print i
my question is:
- are there any *Standard* way to do this? (a buit-in function? a
module?)
- are there any better implements?
thanks for attention :)

Check the itertools module.

HTH

I had checked it for serval times. maybe it's my inattention :-(. but
what i could find the nearest thing is itertools.islice. but it can't
process negative index -- that's supported by slice. so I need
something, bind object with slice, and return a iter. I can find
anything like it...:-(
 
A

Arnaud Delobelle

I had checked it for serval times. maybe it's my inattention :-(. but
what i could find the nearest thing is itertools.islice. but it can't
process negative index -- that's supported by slice. so I need
something, bind object with slice, and return a iter. I can find
anything like it...:-(

Sorry, I read your post too quickly. I don't think there's anything
in the standard library. Your solution is fine!
 
T

Terry Reedy

StarWing said:
I had checked it for serval times. maybe it's my inattention :-(. but
what i could find the nearest thing is itertools.islice. but it can't
process negative index

A negative index -n is an abbreviation for len(sequence) - n.
Since iterables in general do not have a length, islice(iterable) cannot
handle the abbreviation. If you pass a sequence to islice, just
un-abbreviate negative indexes.
 
R

Raymond Hettinger

[StarWing]
. . .
I had checked it for serval times. maybe it's my inattention :-(. but
what i could find the nearest thing is itertools.islice. but it can't
process negative index -- that's supported by slice. so I need
something, bind object with slice, and return a iter. I can find
anything like it...:-(

If it really is a sequence (with len and getitem), you can write your
own indexing iterator:

def myslice(seq, start, stop, step):
'Allow forward or backwards iteration over a subslice'
for i in range(start, stop, step):
yield seq

Raymond
 
S

StarWing

[StarWing]
. . .
I had checked it for serval times. maybe it's my inattention :-(. but
what i could find the nearest thing is itertools.islice. but it can't
process negative index -- that's supported by slice. so I need
something, bind object with slice, and return a iter. I can find
anything like it...:-(

If it really is a sequence (with len and getitem), you can write your
own indexing iterator:

def myslice(seq, start, stop, step):
'Allow forward or backwards iteration over a subslice'
for i in range(start, stop, step):
yield seq

Raymond


Thank you. but it can't support negative index :-(
Terry Reedy is right. since a range (or xrange or slice etc.) don't
have a length, so it can't support a negative index. so the best way
to do it is that binding a range with a object. and return a iter.

I think, why standard library didn't have anything like that, that
will be very useful. maybe we should have a builtin functoin
itertools.bslice (stands for bind slice)...
 
G

Gabriel Genellina

[StarWing]
sometimes I want to iterate a part of a sequence. but don't want to
copy it. i.e. . . .
I had checked it for serval times. maybe it's my inattention :-(. but
what i could find the nearest thing is itertools.islice. but it can't
process negative index -- that's supported by slice. so I need
something, bind object with slice, and return a iter. I can find
anything like it...:-(

If it really is a sequence (with len and getitem), you can write your
own indexing iterator:

def myslice(seq, start, stop, step):
'Allow forward or backwards iteration over a subslice'
for i in range(start, stop, step):
yield seq

Raymond


Thank you. but it can't support negative index :-(
Terry Reedy is right. since a range (or xrange or slice etc.) don't
have a length, so it can't support a negative index. so the best way
to do it is that binding a range with a object. and return a iter.

I think, why standard library didn't have anything like that, that
will be very useful. maybe we should have a builtin functoin
itertools.bslice (stands for bind slice)...


A variation of the code above would do, using a slice() object:

py> def myslice(seq, start, stop, step):
.... 'Allow forward or backwards iteration over a subslice'
.... for i in xrange(*slice(start, stop, step).indices(len(seq))):
.... yield seq
....
py> import string
py> lst = list(string.lowercase)
py> list(myslice(lst, 5, 18, 2)) # as in lst[5:18:2]
['f', 'h', 'j', 'l', 'n', 'p', 'r']
py> list(myslice(lst, -5, None, None)) # as in lst[-5:]
['v', 'w', 'x', 'y', 'z']
py>py> list(myslice(lst, None, None, -1)) # as in lst[::-1]
['z', 'y', 'x', 'w', 'v', 'u', 't', 's', ..., 'a']

Slice objects are not-so-well known, and are documented here:
http://docs.python.org/reference/datamodel.html#types
 
R

Raymond Hettinger

[Raymond]
If it really is a sequence (with len and getitem), you can write your
own indexing iterator:
  def myslice(seq, start, stop, step):
       'Allow forward or backwards iteration over a subslice'
       for i in range(start, stop, step):
           yield seq

[StarWing]
Thank you. but it can't support negative index :-(


The negative index is handled by the line, "yield seq".
s[-2:-5:-1] == ''.join(myslice(s, -2, -5, -1)) True
s[-5:-2:1] == ''.join(myslice(s, -5, -2, 1))
True


Raymond
 
G

Gabriel Genellina

[Raymond]
If it really is a sequence (with len and getitem), you can write your
own indexing iterator:
  def myslice(seq, start, stop, step):
       'Allow forward or backwards iteration over a subslice'
       for i in range(start, stop, step):
           yield seq

[StarWing]
Thank you. but it can't support negative index :-(


The negative index is handled by the line, "yield seq".
s[-2:-5:-1] == ''.join(myslice(s, -2, -5, -1)) True
s[-5:-2:1] == ''.join(myslice(s, -5, -2, 1))
True


But not always:

py> s[10:-1:1]==''.join(myslice(s, 10, -1, 1))
False
py> s[-10:25:1]==''.join(myslice(s, -10, 25, 1))
False

You have to take the sequence length into account before computing the
range, not after.
 

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,983
Messages
2,570,187
Members
46,747
Latest member
jojoBizaroo

Latest Threads

Top