SC:集合,数组,索引,数组消息

一个集合或数组即一个项目组。数组用方括号包围,每个项目由逗号隔开。下边是一个整数数组。

[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)});
Be Sociable, Share!

作者: ww1way

http://about.me/ww1way

发表评论

电子邮件地址不会被公开。 必填项已用*标注