Select a couple of characters within a string to trigger events

Hi,

I’m trying to trigger conditional events based on series of letters occurring during the iteration of a string.
I manage to do it with individual characters, but not with a couple of characters.
These frequencies are put in a list that feeds a synth after.

(var myString, freq, listFreq;
myString = "ACAAGTAGTCATGA";
myString.do({ arg item;
	freq = case
	{item = myString.finds("AA")} {freq = 300}
    {item = myString.finds("AC")} {freq = 400}
    {item = myString.finds("TG")} {freq = 500}
	{item = myString.finds("GA")} {freq = 610};
	listFreq.add(freq);
	~freqList1 = listFreq;
})
)

I tried directly with a string ({item == “AA”} {freq = 300}), it does not throw any error, but it returns an empty list. With the syntax {item = “AA”} {freq = 300}, it throws a Non Boolean in test error.
I tried to concatenate the characters together ({item = $A ++ $A} {freq = 300}), but it also gives me a Non Boolean in test error.
I tried with find or findRegexp, which gives me the same error (which I think I understand because of what the methods return).
With contains, it does not throw an error, but it fills the list with only the first value (300 in this case).

Would someone have any idea?
Thanks!

The items are Char (character) values, not strings. $A == "AA" should be false.

A single = is the assignment operator, not an equality test. So the result of item = "AA" is the string "AA", which is indeed not Boolean.

For two characters, do-ing in pairs may be helpful.

(
var myString, freq, listFreq;
myString = "ACAAGTAGTCATGA";
myString.pairsDo({ arg ch1, ch2;
	var str = String.with(ch1, ch2);
	freq = case
	{ str == "AA" } { freq = 300 }
	{ str == "AC" } { freq = 400 }
	{ str == "TG" } { freq = 500 }
	{ str == "GA" } { freq = 610 };
	// you DO need to reassign to listFreq!
	// See Array help. This is right at the top.
	listFreq = listFreq.add(freq);
});
// you don't need to do this for every loop cycle
// once at the end is enough
~freqList1 = listFreq;
)

-> [ 400, 300, nil, nil, nil, nil, 610 ]

Or, if you want to check AC, CA, AA, AG, GT, replace pairsDo with doAdjacentPairs.

But… nil values. This is because you are always adding to the frequency list, whether or not a valid pair has been found. I’ve made this mistake myself – check for some condition, but then the final action didn’t depend on the condition, so the final action sometimes does the wrong thing.

So maybe:

(
var myString, freq, listFreq;
myString = "ACAAGTAGTCATGA";
myString.pairsDo({ arg ch1, ch2;
	var str = String.with(ch1, ch2);
	freq = case
	{ str == "AA" } { freq = 300 }
	{ str == "AC" } { freq = 400 }
	{ str == "TG" } { freq = 500 }
	{ str == "GA" } { freq = 610 };
	if(freq.notNil) {
		listFreq = listFreq.add(freq);
	};
});
// you don't need to do this for every loop cycle
// once at the end is enough
~freqList1 = listFreq;
)

For more than two characters:

(
var myString, freq, listFreq;
myString = "ACAAGTAGTCATGA";
(myString.size - 2).do { |i|
	var str = myString[i .. i+2];  // 3 characters
	str.postln;
})

hjh

2 Likes

Hi, sorry for the late answer. And thanks for the detailed answer, that’s really helpful.