MicroPython 'uarray' Module

Contents

Introduction

In MicroPython list and array are data structures that are used to store multiple items. The list type is part of the standard MicroPython library while array is exposed by importing the uarray[1] module.


import uarray         
          

A list may contain elements of mixed data types in any combination. For example, a list might contain multiple lists of dictionary elements. A comprehensive discussion of the builtin list type of MicroPython for the micro:bit can be found here.

In contrast, array elements must be all of the same type and must be numerical. Since each element has the same memory requirement as a consequence of all being the same type, items are allocated with contiguous memory locations. Compared to lists, arrays are more memory efficient and retrieving an element by index is much faster.

However unlike list, the micro:bit's MicroPython implementation of the array data type only permits insertion of new elements at the end of the array. This can be quite a limitation and in most cases programmers will choose to use the more flexible list data structure unless speed and/or memory is at a premium.

Basic array Operations

This section will describe how arrays are declared, accessed (indexing and slicing) and looped through.

Declaring

Arrays are declared using the array() function. The uarray module must be imported to make this function available.

Syntax


variable_name = array(typecode,[elements])

Where:
variable_name: The name of the array.

typecode: Specifies the numerical data type.
          See table below.

elements: optional data elements. If no elements
          provided an empty array will be created.

Examples:
import uarray

# An empty integer array
Arr1 = uarray.array('i')
print(Arr1) ⇒ array('i')

# An integer array with two elements
Arr2 = uarray.array('i', [23, 65])
print(Arr2) ⇒ array('i', [23, 65])

# An array populated from a list.
L = [3, 6, 9]
Arr1 = uarray.array('i', L)
print(Arr1) ⇒ array('i', [3, 6, 9])
          

Below is the typecode table that is used to define the different numerical element types that can be stored in a MicroPython array.

Typecode C Python Size
'B' char int 1
'h' signed short int 2
'H' unsigned short int 2
'i' signed int int 2
'I' unsigned int int 2
'l' signed long int 4
'L' unsigned long int 4
'q' signed long long int 8
'Q' unsigned long long int 8
'f' float float 4

As previously mentioned, an array can contain elements of only one data type and it must be a numerical type. Attempting to mix data types in an array results in an error.


import uarray

Arr = uarray.array('i', [23, 46, 3.148])
Causes the following error:
TypeError: can't convert float to int

Arr = uarray.array('i', ['abc'])
Causes the following error:
TypeError: can't convert str to int

Arr = uarray.array('f', [23, 46, 3.148])
print(Arr)
This works because integers
are converted to floats:
array('f', [23.0, 46.0, 3.148])
          

Special mention needs to be made of the 'B' typecode. In a roundabout way it is possible to store characters (and by extension; strings) in an array. If the numerical unicode code of a character is stored in the array it can be retrieved as a character using the decode() method. The micro:bit's MicroPython implementation will only accept unicode codes in the range of 0 to 255. The decode() method will return an error if the code is outside of this range.

The standard MicroPython function ord() or method encode() can be used to find a character's unicode code.

Example 1

# Even though an array must only contain
# numeric data, this program demonstrates
# a roundabout way to store characters
# and strings in an array using
# unicode codes.

import uarray

# Using the ord() function
Arr1 = uarray.array('B', [ord('A'), ord('B'), ord('C')])
# Using the encode() method
Arr2 = uarray.array('B', 'ABC'.encode())

# Print the numeric values
print('Arr1 = ', Arr1)
print('Arr2 = ', Arr2)

# Print the string equivalent
print('Arr1 decoded is:', Arr1.decode())
print('Arr2 decoded is:', Arr2.decode())

          
Output:

Arr1 =  array('B', [65, 66, 67])
Arr2 =  array('B', [65, 66, 67])
Arr1 decoded is: ABC
Arr2 decoded is: ABC
              

Note: Care must be taken when choosing the typecode to use. Adding a number with a larger byte size than that specified by the typecode to the array will not cause an error. However it will lead to unexpected results when it is truncated at the bit-level to fit the allocated memory.

Indexing

As individual elements of a list can be accessed by indexing, so too can array elements. The first element of a list has an index of 0 (zero) which is the same for an array.

The array elements can also be accessed from the end of the array with the use of negative indexes. So the last element in the array has an index of -1, the second last element has an index of -2 and so on. The following example program shows this in action.

Example 2

# Demonstrates accessing elements of
# an array through their index.

import uarray
Arr = uarray.array('i', [10, 20, 30])
print(Arr)
print('First element is:', Arr[0])
print('Last element is:', Arr[2], '\n')

# Access the array elements in reverse
# order using negative indexes.
print('Accessing array elements in reverse order...')
print(Arr[-1], Arr[-2], Arr[-3])
          
Output:

array('i', [10, 20, 30])
First element is: 10
Last element is: 30 

Accessing array elements in reverse order...
30 20 10
          

Arrays are mutable, meaning that they can grow and the values of elements can be changed.

Example 3

# Arrays are mutable so the values
# of elements can change.

import uarray
L = [3, 6, 9]
Arr1 = uarray.array('i', L)
print(Arr1)

# Change the value of
# the second element.
print('Updating the 2nd element...')
print('Original value:', Arr1[1])
Arr1[1] = 27
print('New value:', Arr1[1])
          
Output:

array('i', [3, 6, 9])
Updating the 2nd element...
Original value: 6
New value: 27
          

Slicing

To access a specific range of elements inside the array, the slicing operator, which is a colon ‘:’ is used.

If only a single number is supplied with the slicing operator the first n values of the array will be returned where n is the supplied index. For example Arr[:3] will return the first three elements of the array Arr.

If two numbers are supplied with the slicing operator then all elements starting from the first index up to but not including the second index will be returned.

Negative indexes can also be used with the slicing operator allowing access from the end of the array.

Example 4

# Demonstrates the use of the slicing
# operator ':' on an array.

import uarray

# Define & populate an array.
Num = uarray.array('i',[9, 5, 9, 2, 4, 8])
print('Num:', Num)

# Use the slicing operator with one index.
print('Num[:3] =', Num[:3])

# Use the slicing operator with two indexes.
print('Num[2:5] =', Num[2:5])

# Use the splicing operator
# with negative indexes.
print('Num[-5:-2] =', Num[-5:-2])
          
Output:

Num: array('i', [9, 5, 9, 2, 4, 8])
Num[:3] = array('i', [9, 5, 9])
Num[2:5] = array('i', [9, 2, 4])
Num[-5:-2] = array('i', [5, 9, 2])
          

Note: The slicing operation on an array always returns another array which will be a subset of the original.

Looping through an array

It is a simple process to access each element of an array using a for loop.

Note: Example 5 uses the append() method. This method is discussed below in array Methods, but it simply adds an element to the end of an array. For example Arr.append(5) adds 5 to the end of the array Arr.

Example 5

# An empty array is declared then
# populated with short integers.
# The array is read back element
# by element with them being summed.

import uarray

# Declare an empty array
A = uarray.array('h')

# Populate the array with integers
# from 1 to 5.
for i in range(1, 6):
    A.append(i)
    
print('Array values:', A)

# Loop through the array and
# sum all the elements
sum = 0
for i in A:
    sum +=i
    
print('Sum is:', sum)
          
Output:

Array values: array('h', [1, 2, 3, 4, 5])
Sum is: 15
          

Converting Between array, list and tuple

It is a trivial exercise to convert between array, list and tuple data types using the functions array(), list() and tuple(). The main thing to note however when converting a list or tuple to an array is all the elements of the list or tuple must be numerical and of the same type otherwise an error will result.

Example 6

# Demonstrates converting between
# list, tuple and array data types.

import uarray

L = [1.34, 76.2]
BadList = [4, 'abc']
T = (32, 98)
A = uarray.array('i', [1, 2, 3])

Convert a list to an array
print(uarray.array('f', L))

# Convert a tuple to an array
print(uarray.array('i', T))

# Convert an array to a list
print(list(A))

# Convert an array to a tuple
print(tuple(A))

# This will cause an error because
# the list is not all numerical
print(uarray.array('i', BadList))
          
Output:

array('f', [1.34, 76.2])
array('i', [32, 98])
[1, 2, 3]
(1, 2, 3)
Traceback (most recent call last):
  File "main.py", line 25, in <module>
TypeError: can't convert str to int
          

array Operators

Table 1: MicroPython array Operators
Operator Description
+

Concatenation; inserts the second array to the end of the first array.

A = uarray.array('i', [2, 1])
B = uarray.array('i', [3, 4])
print(A + B)
⇒ array('i', [2, 1, 3, 4])

==

Comparison operator tests whether two arrays are equal

A = uarray.array('i', [0, 1])
B = uarray.array('i', [0, 1])
(A == B) ⇒ True

C = uarray.array('i', [2, 3])
D = uarray.array('i', [3, 2])
(C == D) ⇒ False

!=

Comparison operator tests whether two arrays are not equal

A = uarray.array('i', [0, 1])
B = uarray.array('i', [0, 1])
(A != B) ⇒ False

C = uarray.array('i', [2, 3])
D = uarray.array('i', [3, 2])
(C != D) ⇒ True

array Functions

Table 2: MicroPython array Functions
Function Description
len(array)

Returns the number of elements in an array

len(uarray.array('i', [56, 1, 2]))
⇒ 3

max(array)

Returns the maximum value in an array.

max(uarray.array('i', [56, 1, 2]))
⇒ 56

min(array)

Returns the minimum value in an array.

min(uarray.array('i', [56, 1, 2]))
⇒ 1

sorted(array
      [, reverse =
         True|False])

Returns a sorted copy of the array as a list

A = (uarray.array('i', [56, 1, 2]))

print(sorted(A))
⇒ [1, 2, 56]

print(sorted(A, reverse = True))
⇒ [56, 2, 1]

array Methods

A method, like a function, is a set of instructions that perform a task. The difference is that a method is associated with an object, while a function is not.” [codecademy.com]

This series on MicroPython discusses classes and methods here.

Methods are invoked using dot notation i.e. Array.Method() with the following table providing simple examples. The table provides an exhaustive list of the MicroPython for micro:bit array methods.

Table 3: MicroPython array Methods
Method Description
append(item)

Adds an item to the end of an array. Example 5 demonstrates the use of this method.

A = uarray.array('i', [1, 2])
A.append(4)
print(A) ⇒ array('i', [1, 2, 4])

extend(object)

Add the elements of an object with buffer protocol[2] to the end of an array. MicroPython objects that follow the buffer protocol are bytes, bytearray and array.

# extend with an array object
A1 = uarray.array('i', [1, 2])
A2 = uarray.array('i', [5, 6])
A1.extend(A2)
print(A1)
⇒ array('i', [1, 2, 5, 6])

# extend with a bytes object
A1 = uarray.array('B', [1, 2])
b = bytes(b'\x05\06')
A1.extend(b)
print(A1)
⇒ array('B', [1, 2, 5, 6])

# extend with a bytearray object
A1 = uarray.array('B', [1, 2])
b = bytearray([5, 6])
A1.extend(b)
print(A1)
⇒ array('B', [1, 2, 5, 6])

decode()

Converts the integer elements of an array to a string containing their unicode character equivalents.

The integers must be in the range of 0 (zero) to 255 else an error will occur.

Example 1 covers this in detail.

A = uarray.array('B',[97, 98, 99])
print(A.decode())
⇒ abc