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