Convert symbol to array

I am struggling to find the right conversion here:

a = [1, 2, 1];
b = a.asSymbol
// how do you convert b so that b.someConversion == a?

c = b.asString.interpret;

1 Like

Just to add to what @morgon wrote…
as a general thing, you can’t rely on the symbol representation to be convertible back to the real value. For that you should use [1,2,1].cs, which stands for compile string I believe.

Converting the compile string to a symbol is generally a bad idea, it will work for small object, but with large symbols (greater than 256 characters) you will start to run into hard to find bugs, so best to stick with string.

1 Like

My use case is trying to find patterns of a given length in a (potentially large) list of midinote numbers. I am using the differentiated pattern as the key of an event as a way of tracking equal-but-possibly transposed patterns. I thought it would be a good way to avoid keeping track of all possible patterns which gets astronomically pretty quickly (especially for longer patterns) and only keep track of those actually played. Is this a technique generally used? And is there a better way to find a pattern of a given length in an array of values?

(
c = [0, 2, 1, 5, 4, 7, 9, 8, 0, 1, 3, 2, 4, 3, 1];
// c = { 20.rand }!300; // does not always find a pattern, so run several times
// we can image this being midinotes numbers. Now I want to find a 3-note pattern in the sequence
// with 3 or more occurrences
r = ();
d = c.differentiate;
~pats = ();
(d.size - 3).collect{|i|
	var pat = d[i + 1..i + 2];
	var key = pat.asSymbol;
	if (r[key].notNil)
	{ 
		r[key].add(i);
		if (r[key].size > 2) {  ~pats.add(key -> r[key]) }
	}
	{ r.add(key -> List.new) }
};
~pats.keysDo{|n| ~pats[n].collect{|i| c[i..i + 2 ] }.debug(\pattern) }; // finds the one pattern with 3 occurrences 
""
)

Try using Dictionary instead of () (which is effectively IdentityDictionary for your use case). It should be more than efficient enough, especially if you’re just storing lists of numbers (it has to hash the contents of the arrays, but hashing numbers is cheap).

(
~patternDict = Dictionary();
[10, 100, 1000].do {
    |n|
    "POPULATE n=%".format(n).postln;
    {
        n.do {
            |index|
            ~patternDict.put(
                Array.fill(8, { [0, 3, 5].choose }),
                index
            );
        }
    }.bench;
    "final size is: %".format(~patternDict.size).postln;

    "RECALL n=%".format(n).postln;
    {
        ~patternDict.keys.do {
            |key|
            var index;
            index = ~patternDict[key];
        };
    }.bench;
}
)

It’s also worth remembering that, for many cases where you’re searching a small list of items and where a comparison can be short circuited (e.g. strings and lists, where if the first item matches you move on), it’s actually cheaper or about the same cost to just iterate over every item to search rather than using more complex hashing / dictionary storage.

I tried an example with Dictionary - it feels like the code can be a bit less obfuscated this way?

(
c = [0, 2, 1, 5, 4, 7, 9, 8, 0, 1, 3, 2, 4, 3, 1];
// c = { 20.rand }!300; // does not always find a pattern, so run several times
// we can image this being midinotes numbers. Now I want to find a 3-note pattern in the sequence
// with 3 or more occurrences
r = Dictionary();
d = c.differentiate;
~pats = Dictionary();
(d.size - 3).collect{
    |i|
	var pat, list;
    
    pat = d[i + 1..i + 2];
    r[pat] = list = r[pat].add(i);

    if (list.size > 2) {
        ~pats[pat] = list;
    };
};
~pats.keysDo{|n| ~pats[n].collect{|i| c[i..i + 2 ] }.debug(\pattern) }; // finds the one pattern with 3 occurrences 
""
)

Yes, very clean indeed, thanks!