Array Slice Ranges

Bill Baxter wbaxter at gmail.com
Fri Nov 10 13:42:00 PST 2006


Fredrik Olsson wrote:
> I also like to yet again say that having ranges as a type that can 
> easily be based around would be neat.
> 
> bool checkAge(int age, int min, int max) { ... }
> auto ok = checkAge(bar, 18, 25);
> or
> bool checkAge(int age, int$ range) { ... }
> auto ok = checkAge(bar, 18...25);
> 
> Well how to denote a range type, is something I have not figured out 
> yet. So I went for a $ suffix in the example.
> 
> 
> As an extension, sets is just as useful!
> 
> int<> myFriendsAges = <18, 25, 21>;
> bool foo = allAgesInRangeOver21(myFriendsAges);
> 
> 
> And imagine slicing an array with a set!
> Person[] primePersons = allPersons[<2,3,5,7,11>];

Hmm this got me thinking, why not just use an array?

I beleive I wrote earlier that opIndex didn't work with non-int types. 
Apparently I was wrong.  Sorry for spreading FUD.  I think maybe what 
didn't work was non-int with opSlice, but that's ok, since you can 
easily make opIndex act like a slicer.

So how does this look?

For a Class c containing the array:
     float a[] = [10,11,12,13,14,15,16,17,18,19,20];

c[3]  =                 13
c[[1,4,2,0,7]] =        [11,14,12,10,17]
c[Range(2)] =           [12,13,14,15,16,17,18,19,20]
c[Range(2,4)] =         [12,13]
c[Range(2,8,2)] =       [12,14,16]
c[Range(2,null,2)] =    [12,14,16,18,20]
c[Range(8,2,-2)] =      [18,16,14]

For the plain array we can't overload opIndex, so we have to call a method:
     float a[] = [10,11,12,13,14,15,16,17,18,19,20];

a.slice([1,4,2,0,7]) =       [11,14,12,10,17]
a.slice(Range(2)) =          [12,13,14,15,16,17,18,19,20]
a.slice(Range(2,4)) =        [12,13]
a.slice(Range(2,8,2)) =      [12,14,16]
a.slice(Range(2,null,2)) =   [12,14,16,18,20]
a.slice(Range(2,8,-2)) =     [18,16,14]

You can even index with an array of Ranges! (If you really want to...)
c([Range(4,-1,-2), Range(5,10,2)]) = [14,13,12,11,10,15,16,17,18,19]

Also helpful methods .list and opApply:

Range(0,5).list =        [0,1,2,3,4]
Range(4,null,-1).list =  [4,3,2,1,0]
Range(0,10,2).list =     [0,2,4,6,8]
Range(8,-1,-2).list =    [8,6,4,2,0]
foreach(i,Range(0,10,2)):  0, 2, 4, 6, 8,
foreach(i,Range(8,-1,-2)):  8, 6, 4, 2, 0,
foreach(i,Range(0,null,3)):  0, 3, 6, 9, 12, ...<break>

What's not so hot, could be improved:

D Limitations:
* Can't overload opIndex for built-in arrays :-(

* Can't make the 'slice' function return a plain T for slice(int), 
rather than a T[].  That is, I can't figure out how to do it without 
breaking IFTI, and I think we can agree 
arr.slice!(float[],int[])([4,5,6]) pretty much kills the convenience factor.

* slice can't be extended with new native index types.  In C++ it would 
be possible to add custom specializations of the slice template, so I 
could define my own slice(T[],SetIndex) that would get looked up.  In D 
that gives you an IFTI error (can't specialize automatically deduced 
type).  The result is that in D it has to all go inside the one mondo 
slice template as static if cases.  3rd parties can't extend the behavior.

Limitations of my implementation:

* I focused on positive ranges, to allow indexing everthing that can be 
reached by a size_t, but a version using signed values might be useful 
too.

* A version that does inclusive ranging might be nice as well, but I 
couldn't think of a good way to do that without just duplicating most of 
the code.  Ooh, maybe you could abuse complex literals for that! 
Range(2, 5i) --> means 2 to 5 inclusive.  Ooh that works, it's in the 
attached file too.

* You could imagine adding to the slice template to support anything 
with an opApply that generates ints.  Or a Set type, or anything for 
that matter.  (But it all has to be added inside that one 'slice' 
template as far as I can tell.)

--bb
-------------- next part --------------
An embedded and charset-unspecified text was scrubbed...
Name: ranges.d
URL: <http://lists.puremagic.com/pipermail/digitalmars-d/attachments/20061111/f3c2e79d/attachment.ksh>


More information about the Digitalmars-d mailing list