7
$\begingroup$

Suppose I have a string str that contains only whitespace-delimited real numbers:

str = " 0\t1.46604\t1.44829\t12.0546\t1.57075\t1.64044\t12.0489\t1.58142";

I would like to convert str to a list of real numbers. One way to accomplish this is to split the string using StringSplit and then Map the function ToExpression across the resulting list:

Map[ToExpression, StringSplit[str]]

which gives the correct output:

{0, 1.46604, 1.44829, 12.0546, 1.57075, 1.64044, 12.0489, 1.58142}

But, is there a cleaner or more efficient way to do this? I will be converting about 100,000 strings str -- each of which are approximately the same length as the example str above -- which will be read as records from a text file (i.e., using OpenRead and Read), so it would be nice if the method is relatively efficient. Thank you for your time!

$\endgroup$
4
  • $\begingroup$ Although, I'm not sure why, ToExpression["{" <> StringReplace[str, "\t" -> ", "] <> "}"] seems to be a tad faster than both StringSplit and StringToDouble methods. $\endgroup$
    – kale
    Sep 2, 2012 at 23:06
  • $\begingroup$ @kale probably because you are only searching for /t, and not for the other possible string separators Whitespace is taken to include spaces, tabs and newlines. $\endgroup$ Sep 2, 2012 at 23:09
  • $\begingroup$ @kale, not clearly faster than StringToDouble in my test. Also probably because there's only one string to expression conversion there $\endgroup$
    – Rojo
    Sep 2, 2012 at 23:10
  • $\begingroup$ @Rojo, Yeah, we're not talking much, but consistently a little faster on my machine. $\endgroup$
    – kale
    Sep 2, 2012 at 23:11

5 Answers 5

12
$\begingroup$
str = " 0\t1.46604\t1.44829\t12.0546\t1.57075\t1.64044\t12.0489\t1.58142";
ToExpression[StringSplit[str, Whitespace]]

(* {0, 1.46604, 1.44829, 12.0546, 1.57075, 1.64044, 12.0489, 1.58142} *)
$\endgroup$
1
  • 2
    $\begingroup$ Nice one +1, I didn't realise ToExpression was listable $\endgroup$
    – Rojo
    Sep 3, 2012 at 13:11
10
$\begingroup$

You could also try

Internal`StringToDouble /@ StringSplit[str]

But I don't think your speed limitation will be in the conversion but in the repeated reading of the records. Just guessing.

If you had some long string perhaps you could also try Flatten@ImportString[str, "Table"]

As of 12.3, the internal function name is Internal`StringToMReal

$\endgroup$
1
  • 1
    $\begingroup$ Careful with this Internal`StringToDouble. I would always use StringTrim before it. I just found that Internal`StringToDouble["-1"] returns -1.0 while Internal`StringToDouble[" -1"], with an extra leading space, returns positive 1.0. $\endgroup$ Jun 8, 2020 at 17:17
5
$\begingroup$

Alternatively, since your data is separated by tabs:

data = "0\t1.46604\t1.44829\t12.0546\t1.57075\t1.64044\t12.0489\t1.58142";
ImportString[data, "TSV"] // First
   {0, 1.46604, 1.44829, 12.0546, 1.57075, 1.64044, 12.0489, 1.58142}
$\endgroup$
2
$\begingroup$

Using ReadList:

str = " 0\t1.46604\t1.44829\t12.0546\t1.57075\t1.64044\t12.0489\t1.58142";
ReadList[StringToStream[str], Number]

 (*{0, 1.46604, 1.44829, 12.0546, 1.57075, 1.64044, 12.0489, 1.58142}*)
$\endgroup$
1
$\begingroup$

Using StringCases:

str = " 0\t1.46604\t1.44829\t12.0546\t1.57075\t1.64044\t12.0489\t\
1.58142";
StringCases[str, NumberString] // ToExpression

{0, 1.46604, 1.44829, 12.0546, 1.57075, 1.64044, 12.0489, 1.58142}

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.