简体   繁体   中英

How to create sub-enumerator with limited scope?

Let's say I have collection with 100 elements. Regular enumerator would iterate over those 100 elements.

I would like to create enumerator (which is based on the regular enumerator, ie it is not per each collection, but rather one, general approach) which scope is from "hehe" to "there" -- and I could have for example iterate over 20 elements in the middle only.

void foo(IEnumerable<int> coll)
{
   var regular_iter = coll.GetEnumerator();
   regular_iter.MoveNext();
   regular_iter.MoveNext();
   // ... 8 more
   var scoped_iter = new ScopeEnumerator(regular_iterator,20);

So in such case when I call "scoped_iter.Reset()" it is reseted to its 0 element (10th for entire collection).

And also it "sees" only elements from 10-30.

The question is -- how to implement such enumerator?

Edit

1.

I need iterator from "here", not from "there", because getting to "there" could be very time consuming. However this is minor thing really, the most problematic is Reset method.

2.

Jon asked about the background. What I really try to achieve is slicing the collection (ie you have the -- let's say -- collection of 10 strings, but you would like to interpret it as collection of 5 elements, each element being collection of 2 strings). Naive algorithm is pretty simple, but also is very inefficient. With collection ~16MB (list of strings) I though about another approach -- simply reinterpreting the data, without copying it. So I would create one iterator which picks every SIZE_OF_SLICE element from entire collection, and also I would create this scoped iterator which would start from the first iterator and go for SIZE_OF_SLICE elements.

This way data will be re-used in place, the only difference would be how you iterate over it. It is sufficient for slicing and it should be fast.

3

I implemented efficient slicing for IList (once you assume you have indexer, it is piece of cake) but it is disturbing me, you cannot (?) provide general efficient algorithm for both list (LinkedList) and arrays (List). So if you are reading this, and have an idea how to do it, do not hestitate to answer, even after 10 years (assuming C# will be still with us).

To get an iterator that only sees elements 10-30, use original.Skip(10).Take(20) , although I don't think you can use Reset on it.

If you need to be able to reset it, just use something like

original.Skip(10).Take(20).ToArray()

To do this with the minimum of effort, you'd basically populate a collection which does support Reset (eg List<T> ) with the iterator, and then return that.

It's slightly trickier to do that lazily - ie the first time you iterate, populate a collection. After the first reset, go into "replay" mode. I'm sure it's feasible - it would just be slightly tricky.

It would be even trickier if you had to support being reset the first time after only (say) 15 elements, then when you hit the 16th element the second time round, going back to the original iterator. Yikes.

If you can scope out exactly what requirements you have, it could be a fun thing to implement though...

EDIT: Just to pull some of the comments into this answer: you can't do this in general without copying the data, because there's no guarantee that the iterator will support being reset at all. Imagine if the iterator is providing data from some random number generator, or it's a live broadcast which isn't being recorded - obviously to replay the data, something would have to copy it.

If you have a particular source implementation in mind, that may be different - but you can't do it through just the IEnumerator<T> interface.

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM