D issues are now tracked on GitHub. This Bugzilla instance remains as a read-only archive.
Issue 4468 - std.string.join() for lazy iterable of strings
Summary: std.string.join() for lazy iterable of strings
Status: RESOLVED FIXED
Alias: None
Product: D
Classification: Unclassified
Component: phobos (show other issues)
Version: D2
Hardware: All All
: P2 enhancement
Assignee: Andrei Alexandrescu
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2010-07-15 17:24 UTC by bearophile_hugs
Modified: 2011-12-21 10:33 UTC (History)
1 user (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this issue.
Description bearophile_hugs 2010-07-15 17:24:25 UTC
This Python code generates a lazy sequence of the first 20 integers (starting from 0), then maps them lazily to strings, and then joins them in a single string:


from itertools import imap
r = imap(str, xrange(20))
result = "".join(r)
print result



The same code can be written in D2:

import std.stdio, std.algorithm, std.conv, std.range, std.string;
void main() {
    auto r = map!("to!string(a)")(iota(20));
    //string result = join(array(r), ""); // OK
    string result = join(r, ""); // error
    writeln(result);
}


But I'd like a std.string.join() able to accept a Range too, so I can use join(r, "") instead of join(array(r), ""), because it's shorter, simpler, natural enough and reduces memory used (and probably increases code performance too).

When the total size of the resulting string is not known because the input is a lazy sequence of strings, then probably join() has to use something like appender() to improve its performance.
Comment 1 bearophile_hugs 2011-02-07 14:33:28 UTC
See also bug 5542
Comment 2 bearophile_hugs 2011-07-30 06:54:17 UTC
This is a very common need. Another example:


import std.range;
void main() {
    auto aa = [1:["hello", "red"], 2:["blue", "yellow"]];
    auto r1 = join(aa.values); // OK
    auto r2 = join(aa.byValue()); // error
}
Comment 3 bearophile_hugs 2011-12-21 10:33:37 UTC
Now in DMD 2.057 this works:

import std.stdio, std.algorithm, std.conv, std.range, std.string;
void main() {
    auto r = map!("to!string(a)")(iota(20));
    //string result = join(array(r), ""); // OK
    string result = join(r, ""); // error
    writeln(result);
}


This line:
auto r = map!("to!string(a)")(iota(20));
is also better written:
auto r = map!text(iota(20));


But this doesn't work still:

import std.range;
void main() {
    auto aa = [1:["hello", "red"], 2:["blue", "yellow"]];
    auto r2 = join(aa.byValue()); // error
}


To make this work there are two solutions:
1) Change byValue() to return a Range.
2) Change join() to accept an opApply too.

The first solution allows to use byValue in many other cases, so I think join() is OK, and I close this bug report.