Using algorithms with ranges

mipri mipri at minimaltype.com
Thu Oct 3 05:20:47 UTC 2019


On Thursday, 3 October 2019 at 04:33:10 UTC, Brett wrote:
> I routinely have to generate data using points sequentially and 
> refer to previous points in the data set, maybe even search 
> them. I also may have to break up the algorithm in to parts.
>
> I'd like to get more in to ranges but I simply do not use them 
> much because I don't know all the fancy stuff that makes them 
> more useful over just doing it manually(usually for loop or 3).
>
>
> Is there a way to express an algorithm that generates a data 
> point that may depend on previous data points and "rangify" 
> them?
>
> One usually starts with some integer range: iota(-5,5,1)
>
> The idea then is to be able to generates points off the range 
> but have access to the previous generated points without having 
> to regenerate them(very inefficient).
>
> so if P_k is our kth point then we need to have access to P_j 
> for j < k.
>
...
> Again, if the range code is very complicated and one has to 
> jump through a lot of hoops then it is easier to just do it 
> manually. The main thing I'm interested in is the "History" 
> feature and maybe a way to easily partition the range(range of 
> ranges).

Basic use (which is all I know) of ranges is easy-peasy.  You just
define empty/front/popFront and use it as a range.  You can keep
whatever state you want in addition to that.  I've got a range 
that
internally has an open file handle and PCRE pointers in it. The 
only
complication is that I have to put my destructor code in a normal
function so that both the destructor (in case of unintended use 
that
leaves the GC cleaning things up) and exhausting the range (in the
intended case) can both call it.

Here:

   #! /usr/bin/env rdmd
   import std.stdio;

   struct iotaPlus(T) {
       import std.range : iota;

       typeof(iota(0,0)) r;
       T[] history;

       this(T a, T b) {
           r = iota(a, b);
       }

       bool empty() {
           return r.empty;
       }

       void popFront() {
           r.popFront;
       }

       T front() {
           T x = r.front;
           history ~= x;
           if (history.length > 1) {
               return x + history[$-2];
           } else {
               return x;
           }
       }
   }

   void main() {
       foreach (x; iotaPlus!int(1, 10))
           writeln(x);
   }

Output:

   1
   3
   5
   7
   9
   11
   13
   15
   17

It'd be nicer to do compose a range over iota, as in

   iota(1, 10).newThingWithHistory

but I don't know how to do that yet. I guess c.f. std.range.retro



More information about the Digitalmars-d-learn mailing list