I have the following string for example:
s = "string"
I'm trying to maintain an iterator to this string object.
it = iter(s)
I know that I can use a loop and increment the it
using next
call
for i in range(0, len(s)):
print(next(it))
This is going to print all the characters in this string.
But I have couple of things that I would like the iterator to do as I do using C++ iterator on std::list
.
1.) To return the element that iterator currently points to.
// In C++, I would do,
std::string str = "string";
std::string::iterator it = str.begin();
*it; // gets the value of element
2.) To get the index of element the iterator is at.
So that I'm able to get the sub-string using Python slicing method:
Eg:
s = "string"
s[0:iter_index_in_integer]
In C++, I could use iterators:
std::string str = "string";
std::string::iterator it = str.begin();
std::string(it, it+3);
Is it possible to increment the iterator in Python like that? If not then I could use the index of element the iterator currently points to and how would I do that?
Python's built-in do not provide anything that allows you to get the "current element" of an iterator. The only operation that an iterator must support is next
to get the following element and advance the iteration.
However it's quite simple to write your own iterator that implements other operations:
class AugmentedIterator(object):
_sentinel = object()
def __init__(self, iterator):
self.iterator = iterator
self.value = self._sentinel
def __iter__(self):
return self
def __next__(self):
if self.value is not self._sentinel:
self.value, val = self._sentinel, self.value
return val
return next(self.iterator)
def peek(self, default=_sentinel):
if self.value is not self._sentinel:
return self.value
try:
self.value = next(self.iterator)
except StopIteration:
if default is not self._sentinel:
return default
raise
else:
return self.value
Now, given any iterator it
you can wrap it into an AugmentedIterator
and whenever you want you can call peek()
to check the current element.
Note that there is no such thing as end()
, since iterators can easily be infinite. The only way to know whether the iterator doesn't have any more elements is to call next
and see if it raises a StopIteration
.
For your second request you can use itertools.islice
to get a slice of the iterator. Note however that islice
does python slicing, which allows out-of-bounds indexes:
In [19]: list(islice('string', 0, 1000))
Out[19]: ['s', 't', 'r', 'i', 'n', 'g']
Here the index 1000
since it's bigger then the string length is just taken to mean: until the end. This is consistent with slicing:
In [20]: 'string'[:1000]
Out[20]: 'string'
In C++ you'd get an error trying to use it+1000
if the string has length 6. (Not 100% sure, but since pointers are iterables you'd surely get some troubles at least in some circumstances).
In general the itertools
package contains quite a few useful functions (at the end of the documentation there are some recipes using them). Python also provides some iterator related functions such as:
enumerate
: to iterate over elements and get the relative indices. map
/ filter
/ reduce
iter(callable, sentinel)
: allows you to obtain an iterator given a function without arguments:
for chunk in iter(lambda: file_object.read(4096), ''): handle(chunk)
Is equivalent to:
while True: chunk = file_object.read(4096) if chunk == '': break handle(chunk)
You can use built-in enumerate()
function:
for index, element in enumerate(mystring):
print index
print element
You could do something like:
import itertools
s = "mystring"
s2 = ''.join(itertools.islice(s, 0, 3))
But really, rather than attempt to directly translate C++ idioms, you should find the Pythonic way to do whatever it is you want, which will probably end up being more concise anyway.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.