Skip to content

Arrays in Solidity

This example demonstrates different types of arrays in Solidity, their usage patterns, and comparison with mappings.

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract ArrayExamples {
    // Fixed-size array
    uint[5] public fixedArray;

    // Dynamic array
    uint[] public dynamicArray;

    // Array of strings
    string[] public stringArray;

    // Memory array (only in functions)
    function createMemoryArray(uint size) public pure returns (uint[] memory) {
        // Memory arrays must be fixed-size
        uint[] memory memoryArray = new uint[](size);

        // Fill array with some values
        for(uint i = 0; i < size; i++) {
            memoryArray[i] = i + 1;
        }

        return memoryArray;
    }

    // Array operations
    function arrayOperations() public {
        // Push: Add to end of array
        dynamicArray.push(1);
        dynamicArray.push(2);

        // Pop: Remove and return last element
        if(dynamicArray.length > 0) {
            dynamicArray.pop();
        }

        // Length
        uint length = dynamicArray.length;

        // Delete: Resets element to default value (0)
        // but keeps array length unchanged
        if(length > 0) {
            delete dynamicArray[0];
        }
    }

    // Array limitations and gas considerations
    function arrayLimitations() public {
        // Fixed arrays are limited by stack depth (around 16 elements)
        uint[3] memory smallArray = [uint(1), 2, 3];

        // Dynamic arrays can grow but:
        // 1. Push operations cost more gas as size increases
        // 2. Iteration becomes expensive with large arrays
        // 3. Array length is limited by block gas limit

        // Use this array for demonstration
        for(uint i = 0; i < smallArray.length; i++) {
            dynamicArray.push(smallArray[i]);
        }
    }

    // When to use arrays vs mappings
    mapping(uint => uint) public numberMapping;

    function arrayVsMapping() public {
        // Arrays are better when you need:
        // 1. Length/size tracking
        // 2. Iteration over elements
        // 3. Sequential access
        // 4. Push/pop operations

        // Mappings are better when you need:
        // 1. Random access by key
        // 2. Sparse data structures
        // 3. Large number of elements
        // 4. No need for iteration

        // Example: Using mapping
        numberMapping[0] = 100;
        numberMapping[1] = 200;

        // No length property
        // No iteration capability
        // But very efficient key-based access
    }
}

Key Concepts

  1. Array Types

    • Fixed-size arrays: type[N]
    • Dynamic arrays: type[]
    • Memory arrays must be fixed-size
  2. Array Operations

    • push: Add element to end
    • pop: Remove last element
    • length: Get array size
    • delete: Reset element to default
  3. Limitations

    • Fixed arrays limited by stack depth
    • Dynamic arrays limited by gas costs
    • Memory arrays must be fixed-size
    • Array length limited by block gas limit
  4. Arrays vs Mappings

    Arrays better for:

    • Sequential access
    • Known, limited size
    • Need for length tracking
    • Iteration requirements

    Mappings better for:

    • Random access
    • Large datasets
    • Sparse data structures
    • No iteration needed

Best Practices

  1. Use fixed arrays when size is known and small
  2. Consider mappings for large datasets
  3. Be cautious with array growth in loops
  4. Monitor gas costs with large arrays
  5. Use memory arrays for temporary operations

Array Element Removal Examples

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract ArrayRemovalExamples {
    uint[] public numbers;

    // Initialize array for examples
    constructor() {
        numbers = [1, 2, 3, 4, 5];
    }

    // Remove last element (most gas efficient)
    function removeLastElement() public {
        require(numbers.length > 0, "Array is empty");
        numbers.pop();
    }

    // Remove element at specific index by shifting elements
    // [1, 2, 3, 4, 5] remove index 2 -> [1, 2, 4, 5]
    function removeByShifting(uint _index) public {
        require(_index < numbers.length, "Index out of bounds");

        for (uint i = _index; i < numbers.length - 1; i++) {
            numbers[i] = numbers[i + 1];
        }
        numbers.pop();
    }

    // Remove element by copying last element to index
    // [1, 2, 3, 4, 5] remove index 2 -> [1, 2, 5, 4]
    // Note: This changes array order but is more gas efficient
    function removeBySwap(uint _index) public {
        require(_index < numbers.length, "Index out of bounds");

        // Move last element to the index being removed
        numbers[_index] = numbers[numbers.length - 1];
        // Remove the last element
        numbers.pop();
    }

    // Get current array (for testing)
    function getArray() public view returns (uint[] memory) {
        return numbers;
    }
}

Key Points About Array Removal

  1. Pop Last Element

    • Most gas efficient method
    • Only works when order doesn't matter
    • O(1) operation
  2. Shift Elements

    • Maintains array order
    • Gas expensive for large arrays
    • O(n) operation
  3. Swap and Pop

    • Does not maintain order
    • Gas efficient
    • O(1) operation

Choose the removal method based on your specific needs:

  • Use pop() when removing from the end
  • Use shift when order must be maintained
  • Use swap-and-pop when order doesn't matter and gas efficiency is important