How to collect "some" items of a range in an array?

Jonathan M Davis newsgroup.d at jmdavisprog.com
Tue Jan 7 06:39:08 UTC 2025


On Monday, January 6, 2025 1:15:23 PM MST Renato via Digitalmars-d-learn wrote:
> On Monday, 6 January 2025 at 19:58:12 UTC, H. S. Teoh wrote:
> > On Mon, Jan 06, 2025 at 07:30:27PM +0000, Renato via
> > Digitalmars-d-learn wrote:
> >> Is there any Phobos function that collects "some" items of a
> >> range
> >> into an array/slice?
> >> It's kind of embarrassing that I've been trying to find this
> >> for hours
> >> now without success :(.
> > [...]
> >> My use case is to parse a file format where a line is expected
> >> to have 4 items. I am currently using `takeExactly(4)` but
> >> that doesn't let me index on it, so I can only think of doing
> >> inconvenient (and inefficient) stuff like `front,
> >> skip(1).front ...` to avoid having to write my own `toArray`
> >> :D. I couldn't even find a method to take 1 item and advance
> >> the range! Am I just looking at the entirely wrong places
> >> (std.range, std.algorithm.iteration)??
> > [...]
> >
> > What's wrong with just using std.array.array?
> >
> >
> > T
>
> So I was indeed looking at the wrong place. It's not very
> intuitive to me that a function that acts on ranges is not in
> std.range but in std.array.
>
> I guess the idea is to keep std.range pure (all functions take
> and return ranges, not slices/arrays/HashMaps etc.)?

std.range contains the core functions for creating and operating on ranges
which arguably aren't algorithms, whereas std.algorithm has general
algorithms that operate on ranges (and frequently return ranges), though the
distinction is not always as clear as it should be, and there's certainly
some debate as to whether individual functions are where they should be.

std.array generally has functions which operate on arrays, but it also has
functions for generating arrays, and a lot of functions which were
originally intended for arrays have ultimately either ended up in
std.algorithm or had variants of them end up in std.algorithm as they've
been more generalized. What's left in std.array though is typically eager
and returns arrays rather than returning ranges (and many functions in
std.algorithm return lazy ranges, though some are eager in cases where they
return part of the original range rather than a wrapper range).

std.string then has functions for operating on strings, but it has some
overlap with std.array, because strings are arrays, and just like some of
the functions in std.array either got moved to std.algorithm when they were
made more general, or we ended up with more general variants in
std.algorithm, some functions in std.string were made to operate on arrays
in general rather than strings specifically, and so they got moved in
std.array.

All in all, while the basic distinctions are relatively clear, there's
always going to be some debate about which module a particular function
belongs in, and sometimes functions have been moved if it was decided that
they were definitely in the wrong place. And as functions have been made
more general, sometimes the place that the function arguably should be has
changed, and the functions have not always been moved as they've been
changed.

One example would be split. IIRC, it was in std.string originally, becaause
it split on whitespace specifictally. But then it was made more general and
gained an overload that let you indicate what to split on, which made it so
that it was moved to std.array (and a public import was left in std.string
to avoid breaking code). And later, we got splitter, which operates on
ranges in general and returns a lazy range rather than returning an array
like split does. And somewhere in there, we also ended up with split being
expanded to work on ranges in general, but it returns an array, so it still
make sense for it to be in std.array, but it's no longer just operating on
arrays.

In any case, since Phobos in general uses ranges all over the place, it
really doesn't make sense that std.range would have all of the range-related
functions. It just has some of the core ones that are range-specific and
arguably not algorithms (but again, the distinctions can be blurry at
times). And regardless of how clear some of the distinctions between the
modules were originally, those lines have been blurred as the functionality
of some of the functions involved has expanded. So, understanding the basic
distinctions between the various modules helps make it possible to find
stuff more easily, but functions aren't always where you might expect them
to be, depending on what your expectations are.

- Jonathan M Davis





More information about the Digitalmars-d-learn mailing list