Кольцевые списки

Интересной разновидностью списков являются кольца. Если вы раньше занимались программированием, то наверняка сталкивались с кольцевым буфером или кольцевым массивом. Здесь мы узнаем про кольцевой список - это быстро и просто.

В предыдущем разделе о списках мы видели, как можно извлечь из них элементы, используя механизм индексирования:

puts [52, 55, 59][1]

Так, а что произойдет, если вы захотите извлечь индекс 100? Там явно нет элемента с индексом 100, так как у нашего списка только три элемента. Поэтому Sonic Pi вернет вам nil, что означает “ничто”.

Однако, представьте, что у вас есть счётчик, который, подобно номеру текущего такта, постоянно увеличивается. Давайте создадим наш счётчик и наш список:

counter = 0
notes = [52, 55, 59]

Теперь мы можем использовать счётчик, чтобы получить доступ к нотам в нашем списке:

puts notes[counter]

Здорово, мы получили 52. Теперь давайте увеличим наш счётчик и получим другую ноту:

counter = (inc counter)
puts notes[counter]

Супер, теперь мы получили 55 и если мы сделаем так снова, получим 59. Однако, если после этого мы увеличим счётчик ещё раз, мы выйдем за пределы нашего списка и получим nil. Но что, если нам нужно вернуться к началу списка и снова начинать извлекать элементы по кругу? Вот для этого и нужны кольца.

Создание колец

Мы можем создавать кольца одним из двух способов. Либо используем функцию ring с элементами кольца в качестве параметров:

(ring 52, 55, 59)

Либо можем взять обычный список и преобразовать его в кольцо, передав ему .ring сообщение:

[52, 55, 59].ring

Индексирование колец

Как только мы получили кольцо, мы можем использовать его точно так же, как если бы мы использовали обычный список, за исключением того, что можно использовать отрицательные индексы и индексы, превышающие размеры кольца. И они будут повторяться по кругу и всегда указывать на один из элементов кольца:

(ring 52, 55, 59)[0] #=> 52
(ring 52, 55, 59)[1] #=> 55
(ring 52, 55, 59)[2] #=> 59
(ring 52, 55, 59)[3] #=> 52
(ring 52, 55, 59)[-1] #=> 59

Использование колец

Допустим, мы используем переменную для хранения номера текущего такта. Мы можем использовать её в качестве индекса в нашем кольце для извлечения нот, или времени затухания или чего-нибудь полезного, что мы сохранили в нашем кольце, независимо от номера такта, в котором мы находимся в данный момент.

Гаммы и аккорды тоже кольца

Полезно знать, что списки, возвращаемые scale и chord также являются кольцами и позволяют получить к ним доступ с помощью произвольных индексов.

Конструкторы колец

В дополнение к ring существует ряд других функций, которые будут создавать кольца для нас.

Взгляните на их соответствующую документацию для получения дополнительной информации.