Thread overview
How to collect "some" items of a range in an array?
Jan 06
Renato
Jan 06
Renato
Jan 07
Renato
Jan 07
Renato
Jan 06
monkyyy
Jan 10
Dukc
January 06

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 :(.

I think I know how to write this myself (though writing generic stuff on ranges is not exactly straightforward), but surely there is something for this and I am somehow missing it (even AI can't help me)?

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)??

January 06
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

-- 
Recently, our IT department hired a bug-fix engineer. He used to work for Volkswagen.
January 06

On Monday, 6 January 2025 at 19:30:27 UTC, Renato 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 :(.

I think I know how to write this myself (though writing generic stuff on ranges is not exactly straightforward), but surely there is something for this and I am somehow missing it (even AI can't help me)?

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)??

import std;
alias takearray(int i)=(r)=>r.take(i).staticArray!i;
unittest{
    iota(3).takearray!4.writeln;
    iota(5).takearray!4.writeln;
}
January 06
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.)?
January 06
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



January 07
On Tuesday, 7 January 2025 at 06:39:08 UTC, Jonathan M Davis wrote:
>
> 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

Interesting historical context, thanks for letting us know.

My difficulty would've been eased by more documentation and examples (the official docs examples tend) :). Unfortunately, D really lacks in this regard, despite its age.

I might write myself something about how to do basic stuff in D as I learn.
January 07
On Tuesday, 7 January 2025 at 07:55:21 UTC, Renato wrote:

> My difficulty would've been eased by more documentation and examples (the official docs examples tend....


... the official docs examples tend to be too simplistic IMHO as they just print things instead of doing the stuff you normally want to do, like take a range, filter, map, collect results into a container for example.


January 10

On Monday, 6 January 2025 at 19:30:27 UTC, Renato wrote:

>

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.

I suspect you might unknowingly be the victim of autodecoding. If your line is a string, ergo an array of immutable chars (or a wstring), Phobos functions will treat that as a range of dchars. Since reading four Unicode code points (dchars) might potentially consume more than four UTF-8 code points (chars) from the line, the result of takeExactly can't be random access.

You could use .byCodeUnit on your line before giving it to takeExactly. I think takeExactly is random access if it's source range is. However, be aware that this will split any non-ASCII Unicode symbol in the line to multiple characters, all invalid by themselves. It depends on your use case whether this matters or not. If it does, the staticArray solution earlier in this thread is probably what you want instead.