2

This is just an example, I have much more amount of data:

var str = "3.0;4.5;5.2;6.6";
var res = str.split(";");
console.log(res);

The output will be an array of strings. How can I have array of numbers without going through the existing array again?

user3719454
  • 994
  • 1
  • 9
  • 24
  • This is an exsisting post: https://stackoverflow.com/questions/15677869/how-to-convert-a-string-of-numbers-to-an-array-of-numbers – C4mps Dec 14 '18 at 10:31
  • 4
    This question is different from both of those questions, because of the *"**without going through the existing array again**"*. – T.J. Crowder Dec 14 '18 at 10:41
  • 3
    In 99% of cases people add these restrictions because they mistakenly think that avoiding loops will somehow improve performance, when in fact convoluted solutions without loops are often much worse performancewise. – JJJ Dec 14 '18 at 12:16

5 Answers5

6

...without going through the existing array again?

That's tricky. You can't with split, because split produces an array of strings. You could do it in a single pass with a regular expression, building the array yourself:

var rex = /[^;]+/g;
var str = "3.0;4.5;5.2;6.6";
var match;
var res = [];
while ((match = rex.exec(str)) != null) {
  res.push(+match[0]);
}
console.log(res);

Or actually, that's more overhead than necessary, just indexOf and substring will do:

var str = "3.0;4.5;5.2;6.6";
var start = 0, end;
var res = [];
while ((end = str.indexOf(";", start)) !== -1) {
  res.push(+str.substring(start, end));
  start = end + 1;
}
if (start < str.length) {
  res.push(+str.substring(start));
}
console.log(res);

KooiInc's answer uses replace to do the loop for us, which is clever.


That said, unless you have a truly massive array, going through the array again is simpler:

var res = str.split(";").map(entry => +entry);

In the above, I convert from string to number using a unary +. That's only one of many ways, and they have pros and cons. I do a rundown of the options in this answer.

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • *(Doh! If you see an over-complicated regex above, hit refresh. Clearly need more tea this morning...)* – T.J. Crowder Dec 14 '18 at 10:39
  • 2
    `while ((match = rex.exec(str))` => well, you're not going trough the existing `Array`, I'll give you that, but aren't you just going trough a new `Array` (of matches)? Maybe look at _transducers_ (https://medium.com/javascript-scene/transducers-efficient-data-processing-pipelines-in-javascript-7985330fe73d)? – KooiInc Dec 14 '18 at 10:44
  • @KooiInc - Not *going through* a new array, no. Creating, accessing an entry from, and throwing away, yes. Which is one of the reasons for my *"...unless you have a truly massive array, going through the array again is simpler:..."* :-) You could, of course, do it without a regular expression, too. – T.J. Crowder Dec 14 '18 at 10:46
  • 1
    @KooiInc - Added a non-regex version. No need for regex here. – T.J. Crowder Dec 14 '18 at 10:53
5

You can use map():

var str = "3.0;4.5;5.2;6.6";
var res = str.split(";").map(Number);
console.log(res);
Mamun
  • 66,969
  • 9
  • 47
  • 59
  • 2
    @C4mps - Probably because the OP specifically said *"... **without going through the existing array again**"*. This does exactly what the OP said they didn't want to do. Otherwise, the question would be a duplicate of about 50 other questions. – T.J. Crowder Dec 14 '18 at 10:32
  • 1
    If you want to convert, or more simply get data from an array, you'll always have to go through it... I cannot see a more simple solution than this one. It does exactly what the OP wants. – C4mps Dec 14 '18 at 10:34
  • 3
    @C4mps - No, again, it does exactly what the OP said they **didn't** want. You can absolutely convert the numbers in that string to an array of numbers in a single pass. See Nick Parson's answer (although it does make two passes through the *data*, just not an array), or mine (truly single pass). – T.J. Crowder Dec 14 '18 at 10:35
  • 1
    Yes, I like your solution. My point was that the .map function does the job in one single pass :) so using .map function is the best solution in this case. – C4mps Dec 14 '18 at 10:40
  • 1
    @C4mps - Please read the question carefully. It's clear the OP wants to make a **single** pass through the data, not **two passes**. This answer makes **two passes**: `split` and `map`. (In fact, Nick Parson's answer is two-pass as well, I shouldn't have mentioned it above.) And again, if `map` were the answer, then answering is pointless: Instead, VTC as a duplicate of any of the many existing questions without the OP's restriction. – T.J. Crowder Dec 14 '18 at 10:42
  • Yes I am aware of that. I up voted your answer. – C4mps Dec 14 '18 at 10:45
4

You could replace all the ; using regex with , and then use JSON.parse() to convert it to an array of numbers:

var str = "3;4;5;6".replace(/;/g, ',');
var res = JSON.parse("["+str+"]");
console.log(res);

Do note though, in terms of its efficiency, this isn't any better than using a simple .map to go through the array again.

Nick Parsons
  • 45,728
  • 6
  • 46
  • 64
  • not sure if OP wanted something effecient or just another way of doing this. Pretty sure this doesn't count as being efficient – Nick Parsons Dec 14 '18 at 10:35
  • To be fair, this is still two passes through the **data** (one for `replace`, another for `parse`). But it does technically not go through the *array* twice. – T.J. Crowder Dec 14 '18 at 10:35
  • 1
    ah, yeah *technically*, so not any better than using map I suppose – Nick Parsons Dec 14 '18 at 10:36
2

Another idea without split:

const str2Numbers = (str, numbers = []) => 
 str.replace(/[^;]+/g, a => numbers.push(+a)) && numbers;
console.log(str2Numbers("3.0;4.5;5.2;6.6;3421"));
KooiInc
  • 119,216
  • 31
  • 141
  • 177
  • **Nice**, using `replace` to do the loop. That was floating around the back of my mind at one point and for some reason didn't land. You don't need the capture group (you aren't using it) or the `&& a`, and the regex can be simpler (in case there are numbers like `32;.1`: `const str2Numbers = (str, numbers = []) => str.replace(/[^;]+/g, a => numbers.push(+a)) && numbers;` – T.J. Crowder Dec 14 '18 at 11:09
  • 1
    Thnx @T.J.Crowder, edited. I think I also needed more ... well ... _coffee_, in my case ;) – KooiInc Dec 14 '18 at 11:20
-2

That's tricky. You can't with split, because split produces an array of strings.

var str = "3.0;4.5;5.2;6.6";
var res = str.split(',').map(function(number) {
    console.log(res);
    return parseInt(number, 10);    
});
Asad Khan
  • 98
  • 10
  • What's the purpose of copying the opening line of my answer, followed by the same (incorrect) solution Mamun posted 20 minutes earlier, which does exactly what the OP said they didn't want to do and doesn't relate in any way to the part of my answer you copied? – T.J. Crowder Dec 14 '18 at 11:50