Arrays

Arrays are ordered collections of elements of the same type. They provide efficient storage and access to sequential data.

Array Basics

Arrays in Charl store multiple values of the same type in a single variable.

Creating Arrays

// Array literal syntax
let numbers = [1, 2, 3, 4, 5]

// Explicit type annotation
let floats: [float] = [1.0, 2.0, 3.0]

// Array of strings
let names: [string] = ["Alice", "Bob", "Charlie"]

// Array of booleans
let flags: [bool] = [true, false, true, true]

// Empty array (requires type annotation)
let empty: [int] = []

// Single element array
let single = [42]

Type Homogeneity: All elements in an array must have the same type. Mixed-type collections require tuples.

Array Type Syntax

Array types are denoted with square brackets around the element type: [Type]

Type Description Example
[int] Array of integers [1, 2, 3, 4]
[float] Array of floats [1.0, 2.5, 3.14]
[bool] Array of booleans [true, false, true]
[string] Array of strings ["a", "b", "c"]
[[int]] 2D array (nested) [[1,2], [3,4]]

Accessing Elements

Access array elements using zero-based indexing with square brackets.

Index Access

let numbers = [10, 20, 30, 40, 50]

// Access by index (0-based)
let first = numbers[0]    // 10
let second = numbers[1]   // 20
let last = numbers[4]     // 50

// Use in expressions
let sum = numbers[0] + numbers[1]  // 30
let product = numbers[2] * 2       // 60

// Access with variable index
let i = 2
let element = numbers[i]  // 30

Bounds Checking: Accessing an index outside the array bounds will cause a runtime error.

Array Length

let numbers = [1, 2, 3, 4, 5]

// Get array length
let length = len(numbers)  // 5

// Use length in loops
let i = 0
while i < len(numbers) {
    print("Element " + str(i) + ": " + str(numbers[i]))
    let i = i + 1
}

// Access last element safely
let last_index = len(numbers) - 1
let last_element = numbers[last_index]

Array Operations

Iterating Over Arrays

let scores = [85, 92, 78, 95, 88]

// Print all elements
let i = 0
while i < len(scores) {
    print("Score " + str(i + 1) + ": " + str(scores[i]))
    let i = i + 1
}

// Calculate sum
let sum = 0
let i = 0
while i < len(scores) {
    let sum = sum + scores[i]
    let i = i + 1
}
print("Total: " + str(sum))

// Find maximum
let max_score = scores[0]
let i = 1
while i < len(scores) {
    if scores[i] > max_score {
        let max_score = scores[i]
    }
    let i = i + 1
}
print("Maximum: " + str(max_score))

Searching Arrays

let names = ["Alice", "Bob", "Charlie", "David"]
let target = "Charlie"

// Linear search
let found = false
let found_index = -1
let i = 0

while i < len(names) {
    if names[i] == target {
        let found = true
        let found_index = i
        let i = len(names)  // Break out
    }
    let i = i + 1
}

if found {
    print("Found at index: " + str(found_index))
} else {
    print("Not found")
}

// Count occurrences
let numbers = [1, 2, 3, 2, 4, 2, 5]
let target_num = 2
let count = 0
let i = 0

while i < len(numbers) {
    if numbers[i] == target_num {
        let count = count + 1
    }
    let i = i + 1
}
print("Found " + str(count) + " occurrences")

Array Statistics

let data = [12.5, 15.0, 10.5, 18.0, 14.5]

// Calculate mean
let sum = 0.0
let i = 0
while i < len(data) {
    let sum = sum + data[i]
    let i = i + 1
}
let mean = sum / float(len(data))

// Find min and max
let min_val = data[0]
let max_val = data[0]
let i = 1
while i < len(data) {
    if data[i] < min_val {
        let min_val = data[i]
    }
    if data[i] > max_val {
        let max_val = data[i]
    }
    let i = i + 1
}

print("Mean: " + str(mean))
print("Min: " + str(min_val))
print("Max: " + str(max_val))
print("Range: " + str(max_val - min_val))

Nested Arrays

Arrays can contain other arrays, creating multi-dimensional structures.

2D Arrays (Matrices)

// Create 2D array
let matrix: [[int]] = [
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9]
]

// Access elements
let row0 = matrix[0]       // [1, 2, 3]
let element = matrix[1][2] // 6

// Iterate through 2D array
let i = 0
while i < len(matrix) {
    let j = 0
    while j < len(matrix[i]) {
        print("matrix[" + str(i) + "][" + str(j) + "] = " + str(matrix[i][j]))
        let j = j + 1
    }
    let i = i + 1
}

// Matrix dimensions
let rows = len(matrix)       // 3
let cols = len(matrix[0])    // 3

Jagged Arrays

// Arrays with different lengths
let jagged: [[int]] = [
    [1, 2],
    [3, 4, 5],
    [6],
    [7, 8, 9, 10]
]

// Each row can have different length
let i = 0
while i < len(jagged) {
    print("Row " + str(i) + " has " + str(len(jagged[i])) + " elements")
    let i = i + 1
}

// Safe access
let row_index = 1
let col_index = 2
if row_index < len(jagged) && col_index < len(jagged[row_index]) {
    let value = jagged[row_index][col_index]
    print("Value: " + str(value))
}

Arrays in Functions

Arrays can be passed to and returned from functions.

// Function that takes array
fn sum_array(numbers: [int]) -> int {
    let sum = 0
    let i = 0
    while i < len(numbers) {
        let sum = sum + numbers[i]
        let i = i + 1
    }
    return sum
}

// Function returning array statistics
fn array_stats(data: [float]) -> (float, float, float) {
    let sum = 0.0
    let min_val = data[0]
    let max_val = data[0]

    let i = 0
    while i < len(data) {
        let sum = sum + data[i]
        if data[i] < min_val {
            let min_val = data[i]
        }
        if data[i] > max_val {
            let max_val = data[i]
        }
        let i = i + 1
    }

    let mean = sum / float(len(data))
    return (mean, min_val, max_val)
}

// Function with 2D array
fn sum_matrix(matrix: [[int]]) -> int {
    let total = 0
    let i = 0
    while i < len(matrix) {
        let j = 0
        while j < len(matrix[i]) {
            let total = total + matrix[i][j]
            let j = j + 1
        }
        let i = i + 1
    }
    return total
}

// Usage
let nums = [1, 2, 3, 4, 5]
let total = sum_array(nums)  // 15

let values = [1.5, 2.5, 3.5, 4.5]
let stats = array_stats(values)
print("Mean: " + str(stats.0))

Common Patterns

Filtering Arrays

// Get even numbers from array
fn filter_even(numbers: [int]) -> [int] {
    // In practice, building arrays dynamically requires special handling
    // This is a conceptual example
    let result: [int] = []
    let i = 0
    while i < len(numbers) {
        if numbers[i] % 2 == 0 {
            // Add to result
        }
        let i = i + 1
    }
    return result
}

// Count elements matching condition
fn count_positive(numbers: [int]) -> int {
    let count = 0
    let i = 0
    while i < len(numbers) {
        if numbers[i] > 0 {
            let count = count + 1
        }
        let i = i + 1
    }
    return count
}

Array Comparison

// Check if arrays are equal
fn arrays_equal(a: [int], b: [int]) -> bool {
    if len(a) != len(b) {
        return false
    }

    let i = 0
    while i < len(a) {
        if a[i] != b[i] {
            return false
        }
        let i = i + 1
    }
    return true
}

// Find index of value
fn find_index(arr: [int], target: int) -> int {
    let i = 0
    while i < len(arr) {
        if arr[i] == target {
            return i
        }
        let i = i + 1
    }
    return -1  // Not found
}

// Check if array contains value
fn contains(arr: [int], target: int) -> bool {
    let i = 0
    while i < len(arr) {
        if arr[i] == target {
            return true
        }
        let i = i + 1
    }
    return false
}

ML Data Patterns

// Normalize array values
fn normalize_array(data: [float]) -> [float] {
    // Calculate mean
    let sum = 0.0
    let i = 0
    while i < len(data) {
        let sum = sum + data[i]
        let i = i + 1
    }
    let mean = sum / float(len(data))

    // Calculate standard deviation
    let sq_diff_sum = 0.0
    let i = 0
    while i < len(data) {
        let diff = data[i] - mean
        let sq_diff_sum = sq_diff_sum + (diff * diff)
        let i = i + 1
    }
    let variance = sq_diff_sum / float(len(data))
    let std_dev = sqrt(variance)

    // Create normalized array (conceptual)
    // In practice, use tensors for this
    return data
}

// Split array into batches
fn get_batch_size(total: int, batch_size: int) -> int {
    return (total + batch_size - 1) / batch_size
}

// Check if array is sorted
fn is_sorted(arr: [int]) -> bool {
    let i = 1
    while i < len(arr) {
        if arr[i] < arr[i - 1] {
            return false
        }
        let i = i + 1
    }
    return true
}

Arrays vs Tensors

Understanding when to use arrays versus tensors:

Feature Arrays Tensors
Use Case General data storage, lists ML computations, matrices
Element Types int, float, bool, string, etc. float only
Operations Index access, length Matrix ops, autograd
Performance Standard Optimized (BLAS)
// Use arrays for discrete data
let labels = [0, 1, 0, 1, 1]  // Classifications
let names = ["cat", "dog", "cat", "dog", "dog"]

// Use tensors for numerical ML operations
let features = tensor([1.0, 2.0, 3.0, 4.0, 5.0])
let weights = tensor_randn([5, 10])
let output = tensor_matmul(features, weights)

// Convert array to tensor for ML operations
let data_array = [1.0, 2.0, 3.0]
let data_tensor = tensor(data_array)

Best Practices

DO:

  • Check array bounds before accessing elements
  • Use len() to get array length safely
  • Initialize loop counters to 0 for zero-based indexing
  • Use descriptive names for arrays (plural nouns)
  • Consider using tensors for numerical ML operations
  • Handle empty arrays gracefully in functions

DON'T:

  • Access arrays with hardcoded indices without bounds checking
  • Mix types in arrays (use tuples for mixed types)
  • Create deeply nested arrays (>3 levels)
  • Use arrays for heavy numerical computation (use tensors)
  • Forget to handle empty array cases

Next Steps