Введение

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

В этом документе мы рассмотрим один из способов изменения индексов массивов в Julia в соответствии с нашими потребностями. Мы будем использовать пакет OffsetArrays.jl, чтобы сделать то же самое. Репозиторий GitHub для него можно найти здесь.

Используя примеры, встроенные в Julia, мы рассмотрим процесс создания пользовательского индексированного массива в Julia.

Установка пакета

В вашем REPL (доступ к которому осуществляется путем ввода julia в командной строке и работает, только если Джулия находится в вашем PATH) введите:

import Pkg

Затем вы можете установить пакеты OffsetArrays, используя:

Pkg.add(“OffsetArrays”)

Импорт пакета

Чтобы импортировать пакет, просто введите

using OffsetArrays

Теперь пакет импортирован и готов к использованию.

Основное использование

Чтобы создать собственный индексированный массив после импорта пакета, введите:

array_name = OffsetVector([element1, element2, element3, element3], start_index:end_index)

Где element1, 2, 3 и т.д. — элементы массива, start_index — индекс начального элемента массива, а end_index — индекс последнего элемента.

С помощью этого пакета мы даже можем создавать многомерные массивы с такими пользовательскими индексами:

array_name = OffsetArray{Float64}(undef, -1:1, -7:7)

Это создает двумерный массив с 3 строками (с индексами -1, 0 и 1 каждая) и 15 столбцами (с индексами -7, -6, -5 и так далее до 7), содержащими все объекты #undef.

Пример: Круговой список

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

Код имеет комментарии и поясняет наш алгоритм:

using OffsetArrays
# Create a 0-indexed array
a = OffsetVector([‘a’, ‘b’, ‘c’, ‘d’], 0:3)
# 1-based array to compare with and show that it does not work
b = [‘a’, ‘b’, ‘c’, ‘d’]
# Create a function that takes in an array, and cycles through it cycle_count times
function print_circular(array, cycle_count)
# Loop through values of j ranging from 0 to size_of_array*cycle_count-1. This makes j complete the correct number of cycles
# NOTE: it says size(array)[1] because the size function returns a tuple with the 2D dimensions of the array.
# Since we are working with a 1D vector, we are only interested in its x-dimension. This happens to be the 1st element. The tuple returned is 1-based since the core functions of Julia still use 1-based indexing. We have only created a custom array. We have not changed the behaviour of Julia.
    for j in 0:(size(array)[1]*cycle_count)-1
    # Print the element at the j%size th position. This is what gives us the cyclic behaviour. As j increases to any number, the element accessed is the j%size th element. So, j snaps back to 0 when j becomes a multiple of the size. This means that at the end of a cycle, the 0th element is accessed. This is the reason 0-based indexing is necessary.
    print(array[j%size(array)[1]])
    # If we are at the last step of a cycle, print a space character. This is only to make the output easier to see, and the cycles easy to count. This does not affect the circular list in any way.
        if j%size(array)[1] == (size(array)[1]-1)
            print(“ ”)
        end
    end
end
# Test the function on our custom 0-based array and also on our 1-based array for comparison
print_circular(a, 5)
println(“\n”)
print_circular(b, 5)
# OUTPUT:
# The 0-based array works fine, while the 1-based array throws an error.

Последнее примечание

Опять же, как указано в коде, мы не меняем поведение Джулии. Мы по-прежнему можем создавать массивы обычным способом, и они будут начинаться с индекса 1, когда функция возвращает кортеж или массив, его индекс по-прежнему будет начинаться с 1. Мы только создали пользовательский объект, который работает точно так же, как массив, и имеет пользовательские индексы вместо обычного индексирования на основе 1.