June 02, 2010 Re: Combining infinite ranges | ||||
---|---|---|---|---|
| ||||
Posted in reply to Andrei Alexandrescu Attachments:
| On Wed, Jun 2, 2010 at 21:41, Andrei Alexandrescu < SeeWebsiteForEmail@erdani.org> wrote:
> On 06/02/2010 02:29 PM, Philippe Sigaud wrote:
>
>>
>>
>> On Wed, Jun 2, 2010 at 19:57, bearophile <bearophileHUGS@lycos.com <mailto:bearophileHUGS@lycos.com>> wrote:
>>
>> Philippe Sigaud:
>> > What, do you also need the no-arg version of iota?
>> >
>> > :-p
>>
>> I'd like a generator (range) similar to the Python itertools.count,
>> that yields numbers starting from the given number (defaulting to
>> zero) and just goes on and on. You can use it in many situations:
>> http://docs.python.org/library/itertools.html#itertools.count
>>
>>
>> Yes, it's handy. It's one of the first range I made, a year ago.
>>
>
> iota(n, n.max) is close. Well, it's not infinite, but cycle(iota(n, n.max))
> is. Probably a version using BigInt would be most sensible.
>
As it's mostly used to enumerate/index ranges or generate some simple numbers, iota(n,n.max) is largely good enough, except, as you said it's not infinite. I never used iota much, it regularly crashed on me in the beginning. I can't remember why.
I don't know if your suggestion of BigInt is a joke or not, but the truth is, I have a version using any numerical type, I called it numberz. numbers is the standard version, numberz!T the templated. It uses T for indexing also (it's a random-access range), which allowed me to do
auto r = numberz(BigInt("1000000000"), BigInt("10000000000"));
auto n = r[BigInt("3000000000")];
Hmm, this doesn't work:
auto i = iota(BigInt("0"),BigInt("10"), BigInt("1"));
But honestly, I just used it to learn ranges and D, and never had a real use
for it. It's just the kind of things that's useful to try, to break out of
some preconceptions (using a size_t to index..., 1u as a step).
As you said, it already takes loooots of iterations to exhaust a long.
Philippe
|
June 03, 2010 Re: Combining infinite ranges | ||||
---|---|---|---|---|
| ||||
Posted in reply to Andrei Alexandrescu | Andrei Alexandrescu: > iota(n, n.max) is close. Well, it's not infinite, but cycle(iota(n, n.max)) is. Probably a version using BigInt would be most sensible. An enumerate() too can be useful (not much tested yet): import std.range: isForwardRange, hasLength, isBidirectionalRange, ElementType; import std.typecons: Tuple; import std.array: front, back, empty, popFront, popBack; /// ... struct Enumerate(R) if (isForwardRange!R) { alias Tuple!(size_t, "index", ElementType!R, "item") TPair; R _range; size_t _index; static if (isBidirectionalRange!R && hasLength!R) immutable size_t _originalEnd; this(R input) { _range = input; static if (isBidirectionalRange!R && hasLength!R) _originalEnd = _range.length - 1; } /// Range primitive implementations. ref TPair front() { return TPair(_index, _range.front()); } /// Ditto bool empty() { return _range.empty(); } /// Ditto void popFront() { _range.popFront(); _index++; } static if (isBidirectionalRange!R && hasLength!R) { /// Ditto ref TPair back() { return TPair(_originalEnd + _index, _range.back()); } } static if (isBidirectionalRange!R && hasLength!R) { /// Ditto void popBack() { _range.popBack(); _index--; } } static if (hasLength!R) { /// Ditto @property auto length() { return _range.length; } } } /// Ditto Enumerate!R enumerate(R)(R input) if (isForwardRange!R) { return Enumerate!R(input); } import std.stdio: write, writeln; void main() { string[] arr = ["y", "n", "y", "n", "y"]; foreach (el; enumerate(arr)) write(el, " "); writeln("\n"); foreach_reverse (el; enumerate(arr)) write(el, " "); writeln("\n"); } I don't know if a reverse iteration on an enumerate can be useful. ----------------------- I have used that to try to implement in D2 this Python code: >>> arr = ["y", "n", "y", "n", "y"] >>> [i for i,el in enumerate(arr) if el == "y"] [0, 2, 4] This is a basic D version, Appender not used: import std.stdio: writeln; void main() { // input data string[] arr = ["y", "n", "y", "n", "y"]; // int[] indexes; foreach (i, item; arr) if (item == "y") indexes ~= i; writeln(indexes); writeln(); } ----------------------- This is a more functional quite bad-looking D2 version, that doesn't work (see http://d.puremagic.com/issues/show_bug.cgi?id=4264 ): import std.stdio: writeln; import std.algorithm: filter, array, map; void main() { // input data string[] arr = ["y", "n", "y", "n", "y"]; auto r1 = filter!((p){ return p.item == "y"; })(enumerate(arr)); auto r2 = map!((p){ return p.index; })(r1); writeln(array(r2)); } Bye, bearophile |
June 03, 2010 Re: Combining infinite ranges | ||||
---|---|---|---|---|
| ||||
Posted in reply to bearophile | On 06/02/2010 07:24 PM, bearophile wrote:
> Andrei Alexandrescu:
>> iota(n, n.max) is close. Well, it's not infinite, but cycle(iota(n,
>> n.max)) is. Probably a version using BigInt would be most sensible.
>
>
> An enumerate() too can be useful (not much tested yet):
No need to write enumerate() - it's zip(iota(0, size_t.max), r).
Andrei
|
June 03, 2010 Re: Combining infinite ranges | ||||
---|---|---|---|---|
| ||||
Posted in reply to Andrei Alexandrescu | Andrei Alexandrescu:
> No need to write enumerate() - it's zip(iota(0, size_t.max), r).
What does it happen if someone gives you the sequence produced by:
zip(r, iota(0, size_t.max))
?
You have can require an adaptor because it's not the standard convention.
While enumerate() always gives you indexes at the first place. And the index/item fields have a standard name that you remember in your code.
Finding the minimal number of pieces to do something is useful, but sometimes if an operation is common enough it can be useful to give it a new name. It's called chunking.
Inside an expression that can contain other stuff do you prefer to use:
zip(iota(0, size_t.max), items)
or
enumerate(items)
?
The second makes the expression shorter and more readable in its purpose.
Bye,
bearophile
|
June 03, 2010 Re: Combining infinite ranges | ||||
---|---|---|---|---|
| ||||
Posted in reply to bearophile | On 06/02/2010 08:04 PM, bearophile wrote:
> Andrei Alexandrescu:
>> No need to write enumerate() - it's zip(iota(0, size_t.max), r).
>
> What does it happen if someone gives you the sequence produced by:
> zip(r, iota(0, size_t.max))
> ?
> You have can require an adaptor because it's not the standard convention.
> While enumerate() always gives you indexes at the first place. And the index/item fields have a standard name that you remember in your code.
>
> Finding the minimal number of pieces to do something is useful, but sometimes if an operation is common enough it can be useful to give it a new name. It's called chunking.
>
> Inside an expression that can contain other stuff do you prefer to use:
> zip(iota(0, size_t.max), items)
> or
> enumerate(items)
> ?
> The second makes the expression shorter and more readable in its purpose.
>
> Bye,
> bearophile
My point was that there's no need to sit down and implement functionality. Just write
auto enumerate(R)(R r) if (isInputRange!R)
{
return zip(iota(0, size_t.max), r);
}
Andrei
|
June 03, 2010 Re: Combining infinite ranges | ||||
---|---|---|---|---|
| ||||
Posted in reply to Andrei Alexandrescu | Andrei Alexandrescu:
> My point was that there's no need to sit down and implement functionality. Just write
>
> auto enumerate(R)(R r) if (isInputRange!R)
> {
> return zip(iota(0, size_t.max), r);
> }
Right, thank you. A std lib can contain even small functions/HOFs (that are the result of combination of few other things), if they are very commonly useful.
Bye,
bearophile
|
June 03, 2010 Re: Combining infinite ranges | ||||
---|---|---|---|---|
| ||||
Posted in reply to Andrei Alexandrescu | On Wed, 02 Jun 2010 20:21:49 -0500, Andrei Alexandrescu wrote: > > My point was that there's no need to sit down and implement functionality. Just write > > auto enumerate(R)(R r) if (isInputRange!R) { > return zip(iota(0, size_t.max), r); > } Should this work with v2.043? I get an error if I try to enumerate an array, for example: /* example.d */ import std.range; auto enumerate(R)(R r) if (isInputRange!R) { return zip(iota(0, size_t.max), r); } void main() { auto e = enumerate([10,20,30]); } $ dmd example.d /usr/include/d/dmd/phobos/std/range.d(1773): Error: cannot implicitly convert expression (&this.ranges._field_field_0.front) of type uint delegate() to uint* (The error message is unfortunate: it doesn't indicate the offending expression in example.d.) Thanks, Graham |
June 03, 2010 Re: Combining infinite ranges | ||||
---|---|---|---|---|
| ||||
Posted in reply to Graham Fawcett | On 06/03/2010 10:01 AM, Graham Fawcett wrote:
> import std.range;
>
> auto enumerate(R)(R r) if (isInputRange!R) {
> return zip(iota(0, size_t.max), r);
> }
>
> void main() {
> auto e = enumerate([10,20,30]);
> }
I cry bug.
Andrei
|
June 03, 2010 Re: Combining infinite ranges | ||||
---|---|---|---|---|
| ||||
Posted in reply to Andrei Alexandrescu | On Thu, 03 Jun 2010 10:15:33 -0500, Andrei Alexandrescu wrote:
> On 06/03/2010 10:01 AM, Graham Fawcett wrote:
>> import std.range;
>>
>> auto enumerate(R)(R r) if (isInputRange!R) {
>> return zip(iota(0, size_t.max), r);
>> }
>>
>> void main() {
>> auto e = enumerate([10,20,30]);
>> }
>
> I cry bug.
LOL! Andrei, you are a very terse guy. :)
Do you cry a bug in my example, in std.range, or D 2.043?
Graham
|
June 03, 2010 Re: Combining infinite ranges | ||||
---|---|---|---|---|
| ||||
Posted in reply to Graham Fawcett | On 06/03/2010 10:25 AM, Graham Fawcett wrote:
> On Thu, 03 Jun 2010 10:15:33 -0500, Andrei Alexandrescu wrote:
>
>> On 06/03/2010 10:01 AM, Graham Fawcett wrote:
>>> import std.range;
>>>
>>> auto enumerate(R)(R r) if (isInputRange!R) {
>>> return zip(iota(0, size_t.max), r);
>>> }
>>>
>>> void main() {
>>> auto e = enumerate([10,20,30]);
>>> }
>>
>> I cry bug.
>
> LOL! Andrei, you are a very terse guy. :)
>
> Do you cry a bug in my example, in std.range, or D 2.043?
My code sucks.
Andrei
|
Copyright © 1999-2021 by the D Language Foundation