Data Structure Operations

This chapter covers two data structure operations: slicing and concatenation. Manipulation of these structures provides opportunities to create interesting musical changes.

Procedure

List Operations are a set of tools for modifying a list. We performed similar operations on strings in Chapter 13. Slice notation can be used to create a subset of a list from a larger, existing list. Its syntax is newList = oldList[startIndex: endIndex]. As with string slices, the indices for slice notation are inclusive and exclusive, respectively.

Array Operations are a set of methods for modifying an array. We performed similar operations on strings in Chapter 13. Dot notation and the slice method can be used to slice out an array from a larger, existing array. Its syntax is newArray = oldArray.slice(startIndex, endIndex). As with string slices, the indices are inclusive and exclusive, respectively.

Lists can also be combined with the concatenation operator (+). The syntax is newList = listA + listB.

Arrays can also be combined using the concat method. The syntax is newArray = arrayA.concat(arrayB).

Let’s work through an example that uses concatenation and slicing. This example uses a new operator, modulo. The modulo operator (%) returns the remainder of the division of two numbers instead of the quotient. For example, 7 % 3 = 1 and 8 % 3 = 2. This operator is useful for counting in cycles, like executing a block of code only every third measure.

The example below creates a beat that dynamically changes. Notice makeBeat() 's beat string contains numbers other than 0; it is accessing different indices of the drumSounds list. Every four measures, the last element of drumSounds is moved to the beginning of the list, so makeBeat() 's output changes. This is achieved by slicing two lists from drumSounds, lastSound and allButLastSound. The last element of the drumSounds list is sliced by using a starting index of len(drumSounds) - 1 and an ending index of len(drumSounds). The resulting lastSound list is then concatenated to the front of the allButLastSound list, to make a new version of drumSounds. The if statement condition measure % 4 == 0 means this switch will only happen every 4 measures (when the value of measure divided by 4 has no remainder).

The example below creates a beat that dynamically changes. Notice makeBeat()’s beat string contains numbers other than 0; it is accessing different indices of the `drumSounds array. Every four measures, the last element of drumSounds is moved to the beginning of the array, so makeBeat()’s output changes. This is achieved by slicing two arrays from `drumSounds, lastSound and allButLastSound. The last element of the drumSounds array is sliced by using a starting index of drumSounds.length - 1 and an ending index of drumSounds.length. The lastSound array is then concatenated to the front of the allButLastSound array, to make a new version of drumSounds. The if statement condition measure % 4 === 0 means this switch will only happen every 4 measures (when the value of measure divided by 4 has no remainder).

# List Operations: Using list operations to change our drum sounds every four measures

# Setup
from earsketch import *
setTempo(120)

# Music
drumSounds = [OS_CLAP01, OS_CLOSEDHAT01, OS_COWBELL01, OS_KICK01, OS_LOWTOM01, OS_SNARE01]
beatString = "5-5132-034550011"

for measure in range(1, 33):
    makeBeat(drumSounds, 1, measure, beatString)
    if (measure % 4) == 0:  # Only True at every fourth measure
        # rotate list items so last item moves to first slot
        listLength = len(drumSounds)
        lastSound = drumSounds[listLength - 1 : listLength]
        allButLastSound = drumSounds[0 : listLength - 1]
        drumSounds = lastSound + allButLastSound
// Array operations: Using array operations to change our drum sounds every four measures

// Setup
setTempo(120);

// Music
var drumSounds = [OS_CLAP01, OS_CLOSEDHAT01, OS_COWBELL01, OS_KICK01, OS_LOWTOM01, OS_SNARE01];
var beatString = "5-5132-034550011";

for (var measure = 1; measure < 33; measure++) {
    makeBeat(drumSounds, 1, measure, beatString);
    if (measure % 4 == 0) { // Only true at every 4th measure
        // rotate array items so last item moves to first slot
        var arrLength = drumSounds.length;
        var lastSound = drumSounds.slice(arrLength - 1, arrLength);
        var allButLastSound = drumSounds.slice(0, arrLength - 1);
        drumSounds = lastSound.concat(allButLastSound);
    }
}

Chapter 19 Summary

  • Lists can be concatenated and sliced using list operations, a set of tools for modifying a list.

  • The syntax for creating a subset of a list from a larger, existing list is newList = oldList[startIndex: endIndex].

  • Lists can be combined using the concatenation operator, +, like newList = listA + listB.

  • The modulo operator is used to obtain the remainder after dividing one number by another, rather than the quotient.

  • Arrays can be concatenated and sliced using array operations, a set of tools for modifying an array.

  • The syntax for slicing out an array from a larger, existing array is newArray = oldArray.slice(startIndex: endIndex).

  • Arrays can be combined using the concat method, like newArray = arrayA.concat(arrayB).

  • The modulo operator is used to obtain the remainder after dividing one number by another, rather than the quotient.

Questions

Which of the following operations is used to join lists/arrays?

  • Concatenation

  • Slicing

  • Modulo

  • Addition

Which of the following evaluates to True?

  • 100 % 10 == 0

  • 10 % 10 == 1

  • 10 % 1 == 10

  • 100 % 10 == 1