In Python, you can call the string.join()
method on any iterable, like so:
",".join(some_iterable)
The argument may be a list, generator, or any other object as long as it is iterable.
Playing around with ES6, I couldn't find a way to do so without having to create an array first, I had to do something like this:
function *myGenerator() { ... }
let output = [...myGenerator()].join(",");
I know that join()
is an Array.prototype
method. Is it possible for me to call join()
or some equivalent to concatenate the values generated by myGenerator
without having to create an intermediate array, like the python example above?
In Python, you can call the string.join()
method on any iterable, like so:
",".join(some_iterable)
The argument may be a list, generator, or any other object as long as it is iterable.
Playing around with ES6, I couldn't find a way to do so without having to create an array first, I had to do something like this:
function *myGenerator() { ... }
let output = [...myGenerator()].join(",");
I know that join()
is an Array.prototype
method. Is it possible for me to call join()
or some equivalent to concatenate the values generated by myGenerator
without having to create an intermediate array, like the python example above?
-
2
You can just add a function that implements that to
String.prototype
asjoin
, if you want to; then you could call','.join(myGenerator())
. But you'll at some point either have to create an array to use that join method, or write your own equivalent. And under the hood, I believe the CPython equivalent does create an intermediate array, as that's more efficient than creating lots of intermediate strings instead. – jonrsharpe Commented Jul 9, 2018 at 22:54 - @jonrsharpe I believe that, in theory, you don't need an intermediate array. If what I'm asking is not achievable at present, then this seems like an overlooked feature of the generators implementation, no? – Nasser Al-Shawwa Commented Jul 9, 2018 at 23:01
- 1 No, you don't need the array, you could perfectly well write a function that just consumes the iterator and builds the equivalent string. But that builds lots of intermediate strings instead, which is likely less efficient overall. And either way, if that's what you want to write, what is stopping you writing it? – jonrsharpe Commented Jul 9, 2018 at 23:02
- An answer to your literal question and not the spirit of your question is, you could have a function that takes an iterator, iterates over it, concatenating with a string while adding separators. – CertainPerformance Commented Jul 9, 2018 at 23:03
-
2
@jonrsharpe You're right, nothing is stopping me from writing it myself, I'm just curious to know if there's an ES6 feature that allows me to join on generators just like I can with
Array.prototype.join()
. – Nasser Al-Shawwa Commented Jul 9, 2018 at 23:08
1 Answer
Reset to default 7The ments above answer your question pretty well. However, I was curious about @jonrsharpe's ment about generating intermediate strings and was wondering how that actually affected performance. So I put a join
method on the prototype of a generator and tested it.
Here's the join()
code:
function* nGen(start, stop) {
while (start < stop) {
yield start
start++
}
}
nGen.prototype.join = function(sep) {
let res = this.next().value
for (let v = this.next(); !v.done; v = this.next()) {
res += sep + v.value
}
return res
}
let g = nGen(2, 20)
console.log(g.join(','))
The original jsPerf tests in Safari and Chrome showed this working faster than the very mon idiom: [...g].join(',')
. In a JSBench test in 2022, results were inconsistent between Chrome, Firefox, and Edge, but this method is now slower than [...g].join(',')
and/or a for
loop.
I am far from a master of writing jsPerf/JSBench tests, so maybe I'm screwing something up or misinterpreting the result. But if you're interested: https://jsbench.me/zlkz8tm6vw/1