Its a nice idea.. Sometimes I have exactly that problem.
However, I see some improvements in your implementation:
AsLLEStruct / AsLLERef is not very intuitive. Just take a look at the Enumerable class of the .Net framework and find a name that fits into the naming pattern.
I would call it "EumerateContextAware", "EnumerateWithContext" or something ...
even ValueTypes must return null for lead and lag outside the enumerable
This behavior is in conflict with that of IEnumerator.Current. The value should be undefined if out of bounds.
Current is undefined under any of the following conditions:
The enumerator is positioned before the first element in the collection, immediately ...
As mentioned, expanding the iterable into a list is probably not always desired.
Also a class seems to be overkill, since it needs to carry around an instance dict that's not being used.
An implementation as a generator function seems more lightweight and feasible.
def enumerate(iterable, start=0):
for item in iterable:
yield (start, item)
First of all, I could not reproduce your results, as I got a single output, that was slightly simplified.
The main problem in your code is that ''.ispace() returns False, so we simply need to adjust the condition to not line or line.ispace().
The next problem is that if you did end up starting on a space line, par=, which results in '' when ...
I think this is mistake:
self.iterable = list(iterable)
It requires loading the entire iterable into memory. Being able to avoid this and work with large collections efficiently is one of the big benefits of iterators.
It won't work on non-ending iterators like itertools.count()
If instead, you make an iterator from the iterable, you can avoid both those ...
Takning all considerations by VisualMelon and Pieter Witvoet into account a solution could now be:
static public IEnumerable<T> SkipLast<T>(this IEnumerable<T> data, int count)
if (data == null) throw new ArgumentNullException(nameof(data));
if (count <= 0) return data;
if (data is ICollection<T> collection)
There are 2 cases for which both your and VisualMelon's implementation can be improved:
If count is less than or equal to 0, then you can return source directly. This speeds up iteration by removing an unnecessary intermediate step. For this to work, the yielding part of the method has to be moved into another method, but that's easy with local functions.
if (data == null || count < 0) yield break;
This behaviour is somewhat consistent with Take, but not with Skip: Skip treats a negative values as a zero. As, indeed, does the SkipLast which doesn't appear in .NET Framework.
It should throw on a null argument with an ArgumentNullException.
My only other real issue with the methods is that neither will ...
For Python 2.7 the above code is slightly modified and improved:
__next__() -> next()
self.iterator = iter(iterator) - for simpler initiation, for example PushBackIterator(range(10)) instead PushBackIterator(x for x in range(10))
names of classes
def __init__(self, iterator):
You are re-inventing the wheel here. Building a custom API for transforming templates is very hard to maintain. You have a for each loop now, but soon you'll need much more language constructs. Save yourself the pain and use T4 instead.
boiler-plate string-based code constructs are hard to maintain
concatenating to a string is bad practice for ...
You’ve got an object leak.
PyObject_GetIter() returns a new instance, which you aren’t calling Py_DECREF() on.
If you pass in an iterable object to your function (a list, a tuple, a dictionary, etc), PyObject_GetIter() will return a brand new iterator over than object. You test the return value, discover it is not NULL, and then lose the returned value, ...