Comparing text wave fields and strings

This appears so trivial, that I am sure I must be overlooking something:

I have two waves: one with a set of numerical values and one with the IDs associated with these values. For all IDs I have multiple values, but the number varies. I would now like to calculate some stats for each of these IDs. It seemed straightforward to me to use the "extract" function to grab the values belonging to a given ID:

Wave values
Wave/T ID_list

Extract/FREE/O values, tempWave, ID_list == "ThisID"

print statsmedian(tempWave)


This gives me an error message along the lines of "trying to use a text wave as a numerical wave".

OK, this strikes me as odd but I've attributed it to the way strings are internally handled by Igor. So I thought there must be some other comparison operator that would compare text waves to strings the way that I can compare numerical waves to numerical values. But I can't find any.

As this seems to me to be one of the most obvious uses of the extract function, I can't shake the feeling that I'm overlooking something very obvious ...

Many thanks,

Christian
Christian,

Igor doesn't do string comparisons with the syntax employed in your code. Instead try the StringMatch function...

Extract /FREE/O values, tempwave, StringMatch(ID_list, "ThisID")

StringMatch will return 1 for a match and 0 for no match.

I haven't tested this with the Extract operation, but, acording to the help file for Extract, it would seem that it should work.

Jeff
Christian,

The comparison operator you have overlooked is cmpstr().
Here is an alternate approach:
duplicate/O values, destwave
destwave = cmpstr( ID_list[p], "ThisID")==0 ? values[p] : NaN
WaveTransform zapNaNs destwave

followed by whatever processing you want. I hope this helps.
Thanks Jeff and S.R.!

I had already tried both StringMatch() and cmpstr() – neither of them work with extract.

As a work around, I used the ?: command to assign unique ID numbers to replace the strings (similar to how S.R. suggested). Those allowed me to use the extract command. It just seems awfully non-intuitive and roundabout. Especially when compared to the simplicity of achieving this in other languages (e.g. Python).

Cheers, Christian
chris wrote:
Thanks Jeff and S.R.!

I had already tried both StringMatch() and cmpstr() – neither of them work with extract.


Sure they do. For example:
Function test()

    Make/O/N=5 numberWave = {1, 2, 3, 4, 5}
    Make/O/N=5/T textWave = {"a", "b", "c", "a", "b"}
     
    Extract/FREE/O numberWave, tempWave, (cmpstr(textWave[p], "a") == 0)
     
    print sum(tempWave)
End


•test() 5

chris wrote:

It just seems awfully non-intuitive and roundabout. Especially when compared to the simplicity of achieving this in other languages (e.g. Python).

If you are familiar with and like Python, I am not surprised that you find Igor complicated. Unlike Python, Igor is a strongly typed language. Its syntax is based on C. There are advantages to strongly typed languages, but for someone that is used to being able to pretty much ignore the type of a variable/object it can seem complicated.

In general, you should also always make sure that you create your wave references (WAVE keyword) of the correct type when you use text, complex, wave reference, and data folder reference waves. Likewise, operations whose output is a wave (eg. Duplicate, Extract, etc.) usually take the various wave type flags (the same ones used by the Make operation).
chris wrote:
I had already tried both StringMatch() and cmpstr() – neither of them work with extract.


Christian,

After reading your last note, I did some testing of Extract with StringMatch as the logical expression and found that it works. Note that Extract will treat multidimensional waves as a wave with all the data laid out in a single column. If the wave used for the logical test is shorter than the wave to be extracted, the last entry in the the test wave will be used as the test for the remainder of the extracted wave. Make sense? Probably not.

Try copying the following in the command line and executing.

Make/T wtext = "ID1"
wtext[10,15] = "ID2"
Make wtest1 = p
Extract wtest1, wtemp, StringMatch(wtext, "ID1")
Edit/K=0 'wtemp';DelayUpdate


The values in wtemp will jump from 9 to 16 otherwise they increment by 1.
aclight wrote:


    Extract/FREE/O numberWave, tempWave, (cmpstr(textWave[p], "a") == 0)



Arg. I had tried that without the "[p]" and with "[]" in place of it, but not "[p]". As I said, I was clearly overlooking a simple solution/stupid mistake.

Regarding Python, I have only recently started using it and only when I hit a wall with Igor.

Thanks!
jtigor wrote:

Make/T wtext = "ID1"
wtext[10,15] = "ID2"
Make wtest1 = p
Extract wtest1, wtemp, StringMatch(wtext, "ID1")
Edit/K=0 'wtemp';DelayUpdate


Mea culpa! I must admit, that I was convinced I had tried exactly that, but I clearly didn't. I must have gotten lost between wtext[], wtext[p] and all. Stupid.

Thanks to all of you for your help - especially as I was clearly overlooking a very basic mistake on my end.

Thanks, Christian