Speeding up StringFromList on a lengthy string

Hello all,
We are trying to convert samples provided by oscilloscope as a string of concatenated ASCII values separated by a comma. The number of samples are over 60K.

To convert the values in this string to a wave of floating values we are using `StringFromList`, as described in the manual.

// This function processes a string (read buffer in this case) and
//      returns a wave of floating numbers


Function   Wave_from_StringFromList ( sample_str )
    String sample_str // A semicolon-separated string list
   
    String separator = ","
    Variable separatorLen = strlen(separator)
    Variable numItems = ItemsInList( sample_str , ",")
    Variable offset = 0
    Variable i

    print "\t number of items in the list : ", numItems
   
    Variable timerRefNum
    variable microSeconds
    timerRefNum = StartMSTimer
   
    make /FREE /d /n=(numItems) temp
    string item
       
    for(i=0; i<numItems; i+=1)
        // When using offset, the index parameter is always 0
        item = StringFromList(0,  sample_str  , separator, offset)

        temp [i] =  str2num(item)
   
        offset += strlen(item) + separatorLen
       
    endfor
   
    microSeconds = StopMSTimer(timerRefNum)
    Print /d microSeconds  /1e6 , " seconds "  
       
    duplicate /o temp out
   
End

////////////////////////////////////////////////////////////////////////

 

This operation takes very long time compared to the actual measurement and data transfer which typically takes <0.1 s. Hence, the iterative conversion process takes considerably long time.

How can we improve the speed of this conversion.

 

// output when running the above function
Wave_from_StringFromList ( root:RTO_str )
     number of items in the list :   61954
  22.6564711   seconds

 

See the attached pxp file for the sample_string saved as a global_variable for testing purpose.

Experiment file with string as a global var (1.57 MB)

How are you capturing the string? Can you capture it into a string wave rather than a string list? Can you force the conversion to a number at the input reading?

In the meantime, I tested an implicit versus explicit for loop.

Function make_wavefromstring( string instr)

    variable timerRefNum, microSeconds, nitems, ic
   
    nitems = ItemsInList(instr,",")
    make/D/FREE/N=(nitems) temp

    timerRefNum = StartMSTimer 
    temp = str2num(StringFromList(p,instr,","))
    microSeconds = StopMSTimer(timerRefNum)
    Print/D microSeconds/1e6 , " seconds with implicit ", nitems
   
    temp = 0

    timerRefNum = StartMSTimer 
    for (ic=0;ic<nitems;ic+=1)
        temp[ic] = str2num(StringFromList(ic,instr,","))
    endfor
    microSeconds = StopMSTimer(timerRefNum)
    Print/D microSeconds/1e6 , " seconds with for loop ", nitems

    return 0

end
•make_wavefromstring(RTO_str)
  15.970029476   seconds with implicit   61954
  15.926372869   seconds with for loop   61954

Perhaps the str2num conversion is the slow step.

 

No, definitely StringFromList() is the bottleneck here. I guess because this function searches through the whole thing each step. Do this instead:

Function make_wavefromstring( string instr)
    variable timerRefNum, microSeconds
    timerRefNum = StartMSTimer
   
    wave/T w = ListToTextWave(instr, ",")
    make/d/o/n=(numpnts(w)) out = str2num(w[p])
   
    microSeconds = StopMSTimer(timerRefNum)
    Print/D microSeconds/1e6, "seconds"
    return 0
end
•make_wavefromstring(RTO_str)
  0.0661931 seconds

 

In Igor Pro 7 or later, StringFromList has an optional offset parameter that can dramatically speed up iterating through lists of many strings. See the DemoQuickStringFromList function in the help for StringFromList.

ListToTextWave is also a good solution.

 

As described by Chozo, StringFromList() is the slow step in this issue. String to number conversion is not the bottleneck.

Converting to text wave  `ListToTextWave` is extremely fast, and practically solves the issue.

Thank you all, in particular chozo,  for the great inputs.