1

For N=1, I would use std.array : empty to check for length being at least N, and avoid having to go through the whole input.

For N>1 (or all N), what is the idiomatic way in D language?

I've tried to use the std.range : take which "Lazily takes only up to n elements of a range.". It works for arrays but not for ranges (unless of course I make a sub-range into an array):

#!/usr/bin/env rdmd

module test_ranges;

void main()
{
    import std.container.dlist : DList;
    assert(lengthAtLeast([1, 2, 3], 2) == true);

    // assert(lengthAtLeast(DList!int(1, 2, 3)[], 2) == true);
    /*
test_ranges.d(64): Error: no property length for type Take!(Range)
test_ranges.d(10): Error: template instance `test_ranges.lengthAtLeast!(Range)` error instantiating
Failed: ["/usr/bin/dmd", "-v", "-o-", "test_ranges.d", "-I."]
    */
}

bool lengthAtLeast(R)(R input, size_t n)
{
    import std.range : take;

    return input.take(n).length == n;

    // this makes it work for arrays and ranges alike, but is not nice, is it?
    // import std.array : array;
    // return input.take(n).array.length == n;
}
V-R
  • 1,309
  • 16
  • 32

1 Answers1

1

walkLength does what you want:

bool lengthAtLeast(R)(R input, size_t n)
{
    import std.range.primitives : walkLength;
    return input.walkLength(n) >= n; // walks upTo n or returns the length if known
}
V-R
  • 1,309
  • 16
  • 32
BioTronic
  • 2,279
  • 13
  • 15
  • 1
    `walkLength` should work for all ranges (except output ranges, but those are a very different beast). Since arrays are ranges, that should cover all your bases. – BioTronic Apr 03 '19 at 13:30
  • From the [hasLength doc](https://dlang.org/library/std/range/primitives/has_length.html) I'm not sure if, in case the given range "has" a length, that it won't actually cost O(whole length) when it wants to return it. I think there are cases when it will be computed by exhausting the entire range! So there might theoretically be an even better answer. – V-R Apr 03 '19 at 13:56
  • 1
    If a range has a `length`, it will be used. Only otherwise, the range will be iterated to count the number of elements. – greenify Apr 03 '19 at 15:09
  • Actually I want to ensure maximum possible time & space efficiency on all kinds of input, so I'm wondering if my approach with `take(n).array` would therefore be better. However probably the `.array` in my approach incurs space inefficiency, so I might need a combined approach via a much more fancy template. – V-R Apr 03 '19 at 16:09
  • 1
    I've tested the different asserts in a tight loop 500K times per input type and the whole program precompiled under [multitime](https://github.com/ltratt/multitime). For sliced `DList` @BioTronic's solution is 1.5x faster than mine, for normal arrays 2x faster than mine. Used (R)DMD 2.082.0 without any switches. – V-R Apr 04 '19 at 11:20