How to make rsplit (like in Python) in D

TheFlyingFiddle via Digitalmars-d-learn digitalmars-d-learn at puremagic.com
Sat Oct 1 11:33:02 PDT 2016


On Saturday, 1 October 2016 at 16:45:11 UTC, Uranuz wrote:
> How to make rsplit (like in Python) in D without need for extra 
> allocation using standard library? And why there is no 
> algorithms (or parameter in existing algorithms) to process 
> range from the back. Is `back` and `popBack` somehow worse than 
> `front` and `popFront`.
>
> I've tried to write somethig that would work without 
> allocation, but failed.
> I have searching in forum. Found this thread:
> https://forum.dlang.org/post/bug-10309-3@http.d.puremagic.com%2Fissues%2F
>
> I tried to use `findSplitBefore` with `retro`, but it doesn't 
> compile:
>
> import std.stdio;
> import std.algorithm;
> import std.range;
> import std.string;
>
> void main()
> {
> 	string str = "Human.Engineer.Programmer.DProgrammer";
> 	
> 	writeln( findSplitBefore(retro(str), ".")[0].retro );
> }
>
> Compilation output:
> /d153/f534.d(10): Error: template std.range.retro cannot deduce 
> function from argument types !()(Result), candidates are:
> /opt/compilers/dmd2/include/std/range/package.d(198):        
> std.range.retro(Range)(Range r) if 
> (isBidirectionalRange!(Unqual!Range))
>
>
> Why I have to write such strange things to do enough 
> wide-spread operation. I using Python at the job and there is 
> very much cases when I use rsplit. So it's very strange to me 
> that D library has a lot of `advanced` algorithms that are not 
> very commonly used, but there is no rsplit.
>
> Maybe I missing something, so please give me some advice)

There are two reasons why this does not compile. The first has to 
do with how retro() (and indeed most function in std.range) work 
with utf-8 strings (eg the string type). When working on strings 
as ranges, the ranges internally change the type of ".front" from 
'char' into 'dchar'. This is done to ensure that algorithms 
working on strings do not violate utf-8.

See related thread: 
http://forum.dlang.org/post/mailman.384.1389668512.15871.digitalmars-d-learn@puremagic.com

The second reason has to do with findSplitBefore called with 
bidirectional ranges.

Now to why your code does not compile.

retro takes as input parameter a bidirectional or random access 
range. Because of how strings are handled, the string type 
"string" is not characterized as a random access range but 
instead as a bidirectional range. So the output from retro is a 
bidirectional range.

Calling findSplitBefore with a bidirectional range unfortunately 
does not return results that are also bidirectional ranges. 
Instead findSplitBefore returns forward ranges when bidirectional 
ranges are given as input. I am not entirely sure why.

The chain of calls has the following types.

string is (bidirectional range) -> retro(str) is (bidirectional 
range) -> findSplitBefore is (forward range)

Now the last call to retro is called with a forward range and 
retro needs bidirectional or random access ranges as input.

If you change the line:
> string str = "Human.Engineer.Programmer.DProgrammer";
into:
dstring str = "Human.Engineer.Programmer.DProgrammer";

Then the code will compile.

The reason for this is:

dstring is (random access range) -> retro(str) is (random access 
range) -> findSplitBefore is (random access range)

Now the last call to retro gets a random access range as input 
and everyone is happy.








More information about the Digitalmars-d-learn mailing list