4

So I'm trying to implement a lazy-evaluating data type (in PHP, though that shouldn't matter any) where you can queue up actions to take on a set of data. This data can come (theoretically) from any traversable object: arrays, generators, and other iterable objects.

So for instance, given a $collection object containing a unsorted array of integers, you could call methods on that object like map($callback) or filter($callback) and it will return a new Collection instance with the action queue of the original collection appended with the called method. No queued actions are executed until the absolute last possible moment, e.g. when the data is actually going to be used for output, reduction to a simple value, and even methods like some/every/find only iterate as much as they need to. This restriction is made easier to implement by the collection (currently) not exposing any sort of index access interface.

The underlying implementation once execution is triggered will try and iterate over the underlying data set as few times as possible by logically grouping the queued operations where possible to avoid creating any intermediate representations of the data as much as possible. So if you have multiple map() operations set up, then it'll compose those. Filter operations can be grouped in to this single execution loop too, all it means is that when the filter/rejection test function fails then the execution ends for that iteration element.

And this all works, right up until one edge case: sorting. Sorting (unless there's a better idea I'm missing here) requires a separate iteration cycle to begin so that the array can begin. Which I don't mind doing, except in certain cases like where I want only, say, exclusively the first n elements of the sorted collection. At that point, it seems to me that there's no way to know what those values are without sorting the entire collection. Is there any way to avoid that? Otherwise it's going to be a waste of (most of) the advantages of lazy evaluation, and I'd like to avoid that...

  • You'll need to fully evaluate the collection (map, filter, etc), however you don't need to fully evaluate the sort. If you're only going to use a few items from the collection, you can sort only the first k elements with a partial sorting algorithm. – zzzzBov Dec 5 '16 at 20:46
5

In short, no, there is no way to do sorting on an incomplete collection unless you will delay sorting until the very end wen the collection is already present.

Longer version: Sorting by definition involves evaluating the entire set of items and arranging them in the right order. I doubt you can do sorting on the the collection without having the entire collection instantiated.

If your collection consists of rather large complex objects, consider having object metadata that is required for sorting available upon sorting, and load the rest of the object data as required later on into the execution cycle.

  • Yeah that's about what I figured, I was just wondering if there might be some clever tactic I wasn't aware of to only partially sort a set of objects. The metadata idea's clever, and I'll definitely keep it in mind for future problems. – moberemk Jun 25 '15 at 1:05
4

Taking clues from LINQ, a typical way to workaround this fundamental impossibility is to implement a Take function, which takes the first N values from the lazy collection (or enumerator) and then process only those N values.

To use it, the user must specify how many values to "take" each time.

Collections which are already sorted or histogrammed (binned in a sorted order) can perform lazy take, because the sorting has already been done.

In some limited use cases, one could do something similar to:

  • Suppose the values are integers in the range 0 - 99, inclusive.
  • To retrieve all items in the range 0 - 9, do a Filter between 0 and 9 inclusive, whose result is then sorted.
  • To retrieve all items in the next range of 10 - 19, do another Filter between 10 and 19 inclusive, and then sort that.

This requires some prior knowledge of the numerical distribution of data, but it does not require a complete sorting (ranking) of all of the data.

In particular, this range filtering approach will not be able to produce correct result unless a lower bound on the numerical data is known. (Any lower bound will work.)

  • But there are 2 issues are still left: 1. To filter, you have to iterate through all the items in the collection otherwise results are not reliable. 2. Why sort the subset if you still need to sort the whole collection(Assuming that's what the OP needs). – Alexus Jun 25 '15 at 0:23
  • I know this increases the complexity quite a bit but I'm curious about how this kind of approach would interact with multiple sorts? For instance on a set of objects with two properties where you were sorting on them both in a specified order of priority? – moberemk Jun 25 '15 at 1:10

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.