一个集合或数组即一个项目组。数组用方括号包围,每个项目由逗号隔开。下边是一个整数数组。
[1, 4, 6, 23, 45]
字符串也可以被做进数组。字符串即一个字符的组,计算机将之视为一个单独的对象。
["One", "Two", "Three", "Four"]
或者你可以做个混合体。注意“34”(在引号内)并不会被SC识别为整数34,而是一个包含字符3和4的字符串。但1,56和3都是整数。
[1, "one", "34", 56, 3]
你同样可以用这个数组进行数学计算。即,数组懂得数学信息。
22.1. 数组算术
(
a = [1, 2, 3, 4]; //申明一个数组
b = (a + 12)*10; //为数组每个项目加12然后乘10
//然后将结果存入b
b.postln;
)
你能预见下面各例的结果吗?
22.2. array.do 和数学
(
a = [60, 45, 68, 33, 90, 25, 10];
5.do(
{
a = a + 3;
a.postln;
}
)
)
22.3. 数组 + 每个项目
(
a = [60, 45, 68, 33, 90, 25, 10];
5.do(
{arg item;
a = a + item;
a.postln;
}
)
)
这有点儿难:在运行下例时预计输出。我正使用两个数组。第一个被存入变量a并被用在函数do里。第二个是被do函数使用的对象。因此项目引数将在第一次迭代时是1,第二次14,19,等等。
22.4. 两个数组
(
a = [60, 45, 68, 33, 90, 25, 10];
b = [2, 14, 19, 42, 3, 6, 31, 9];
b.do(
{arg item;
item.post; " plus ".post; a.post; " = ".post;
a = a + item;
a.postln;
}
)
)
同样可以在一个数组中测试一个值的存在。需要用到的消息是includes。当数组包含某个项目或对象时这个消息回答真。它有一个引数:你要找的对象。因此[1, 2, 3, 4].includes(3)将返回真,而[1, 2, 3, 4].includes(10)将返回假。这些真或假的返回可以被用到if函数内(向我们之前章节中看到的)。
22.5. 测试一个数组
(
a = [60, 45, 68, 33, 90, 25, 10];
b = [25, 14, 19, 42, 33, 6, 31, 9];
100.do(
{arg item;
if(a.includes(item), {item.post; " is in a ".postln});
if(b.includes(item), {item.post; " is in b ".postln});
}
)
)
数组可被用于存储音、频率、持续时间、发音(articulation)或乐器选择的集合。它们可被用于调性、单元格(cell)、集合、序列等与音乐有关的地方。
欲在一个数组内检索一个单独的值,用at消息。at的引数是索引编号。记住计算机是从0开始计数。因此数组[1, 2, 3, 4]有四个项目,索引编号0,1,2和3。数组[9, 12, “this”, 7],索引1是12,索引2是“this”。如果索引数大于数组容量的话你会得到一个nil。这被称作野指示器(wild pointer)。但我们常会有超过数组大小的计数器,在这样的情况下,我们可以用 wrapAt 回到索引模(modulo)数组大小的值的位置。
22.6. 引用数组中的一个项目
[12, 4, 871, 9, 23].at(3) // 索引3是"9" [12, 4, 871, 9, 23].at(124) // 野指示器, 将返回nil [12, 4, 871, 9, 23].wrapAt(124) // 将wrap回去(到索引4)并返回23
数组消息
一下是数组消息集合。
22.7. 数组消息
a = [1, 2, 3, 4]; // 将数组分配到变量"a"
a.post; // 列印数组
a + 5; // 为数组每个项目加5
a*3; // 乘
a.do({arg item; function}) //迭代过每个项目,然后将每个项目传递给函数
a.at(index) // 在给定索引引用项目
// 下边是一些新东西。分别运行每行看看它们是干嘛的:
[1, 2, 3, 4].reverse.postln; // 反转数组
[1, 2, 3, 4].rand.postln;
[1, 2, 3, 4].scramble.postln; // 打乱数组
[1, 2, 3, 4].size.postln;// 返回数组大小 (项目数字)
Array.fill(size, function); //fills an array with "size" number of arguments using function
a = Array.fill(5, {10.rand}); a.postln;
a = Array.rand(12, 0, 12)
[1, 2, 3, 4].add(34).postln; //为数组增加一个项目
//注意add。你需要将之传递给另一个数组变量
//以确保项目已被增加了。 So the code would have to be:
a = [1, 2, 3];
b = a.add(10);
a = b;
[1, 2, 3, 4].choose; //选择其中一个值
[1, 2, 3, 4].put(2, 34).postln; // 将第二引数放在第一引数的索引位置
[1, 2, 3, 4].wrapAt(index) // 返回wrap后的索引位置
//范例:
30.do({arg item; [1, 2, 3, 4].wrapAt(item).postln});
数组引用的一个实际用途即定义变量选择。先前我们用[array].choose,它能将选择限制在数组项目内。接下俩的例子用消息rand做同样的事。第一个返回了一系列数字,0到10。但如果rand被放到at中,那么它的值会变为数组的索引,并且返回在那个索引位置的值。
如我之前提到过的,索引数不能大于数组大小。我们用 wrapAt 解决了一个例子。另一方法是含进消息size,它返回数组的大小,并可被与rand配合使用。size返回的数字将比实际索引数大1。数组[3, 5, 7, 1, 8, 12]的大小为6,但索引是从0到5。这没问题,因为rand从0选取一个数字(未完全翻译,原文为“because rand chooses a number from 0 to, but not including, its receiver.”,我暂时没搞懂他这句话什么意思,很明显这哥们不喜欢用简单易懂的方式写作)。
22.8. 合法音数组
20.do({12.rand.postln;}) // 0 到 11 的随机数
// 随机数选取, 但数组仅从大音阶返回音
20.do({[0, 2, 4, 5, 7, 9, 11].at(6.rand).postln})
// 确保rand的范围不太大
20.do({[0, 2, 4, 5, 7, 9, 11].at(12.rand).postln})
// 未避免范围太大, 使用 array.size 或 wrapAt
a = [0, 2, 4, 5, 7, 9, 11];
20.do({a.at((a.size).rand).postln})
有给at、wrapAt、折叠(fold)和修剪(clip)索引的简写符号。用”@” 和 “|”。|i| 是 arg i 的简写。
22.9. 数组索引简写
[45, 37, 99, 367, 9] @ 3 // "在(at)" 索引 3
[45, 37, 99, 367, 9] @@ 25 // "wrapAt" 索引 25
[45, 37, 99, 367, 9] @|@ 25 // 在索引 25 折叠
[45, 37, 99, 367, 9] |@| 25 // 在索引 25 修剪
30.do({[0, 2, 4, 5, 7, 9, 11] @ (12.rand).postln})
30.do({ |i| ([0, 2, 4, 5, 7, 9, 11] @@ i).postln})
30.do({ |i| ([0, 2, 4, 5, 7, 9, 11] @|@ i).postln})
30.do({ |i| ([0, 2, 4, 5, 7, 9, 11] |@| i).postln})
练习,巴赫变异
消息at同样允许你在不同的度上引用数组项目:每隔一个,每隔两个,等等,就像在对巴赫的作品进行极简篡改所做的那样。
22.10. 合法音符数组
// (预定midi)
(
var pitch;
r = Task({
// 尝试别的版本
pitch = [12, 0, 2, 4, 2, 0, 7, 4, 12, 7, 4, 7, 5, 4, 5, 7, 0, 4, 7, 11] + 60;
inf.do({arg h, i;
pitch.size.do({arg j;
var n;
//逐个, 然后每隔一个, 然后每隔两个,等等.
n = pitch.wrapAt(j*(i+1));
if((j%20 == 19), {n.postln}, {n.post; " ".post});
m.noteOn(1, n, 100);
thisThread.clock.sched(0.1, {m.noteOff(1, n, 100); nil});
0.1.wait;
});
});
})
)
r.start;
r.stop; 127.do({arg i; m.noteOff(1, i)});
