Документация Engee

Сортировка и связанные с ней функции

Julia имеет обширный и гибкий API для сортировки и взаимодействия с уже отсортированными массивами значений. По умолчанию Julia выбирает разумные алгоритмы и выполняет сортировку в стандартном порядке по возрастанию:

julia> sort([2,3,1])
3-element Vector{Int64}:
 1
 2
 3

Кроме того, можно легко сортировать значения и в обратном порядке:

julia> sort([2,3,1], rev=true)
3-element Vector{Int64}:
 3
 2
 1

sort создает отсортированную копию, оставляя входные данные без изменений. Используйте высокопроизводительную версию функции сортировки для изменения существующего массива:

julia> a = [2,3,1];

julia> sort!(a);

julia> a
3-element Vector{Int64}:
 1
 2
 3

Вместо того чтобы напрямую сортировать массив, можно вычислить перестановку индексов массива, которая приведет его в отсортированный порядок:

julia> v = randn(5)
5-element Array{Float64,1}:
  0.297288
  0.382396
 -0.597634
 -0.0104452
 -0.839027

julia> p = sortperm(v)
5-element Array{Int64,1}:
 5
 3
 4
 1
 2

julia> v[p]
5-element Array{Float64,1}:
 -0.839027
 -0.597634
 -0.0104452
  0.297288
  0.382396

Массивы можно легко отсортировать в соответствии с произвольным преобразованием их значений:

julia> sort(v, by=abs)
5-element Array{Float64,1}:
 -0.0104452
  0.297288
  0.382396
 -0.597634
 -0.839027

Или в обратном порядке путем преобразования:

julia> sort(v, by=abs, rev=true)
5-element Array{Float64,1}:
 -0.839027
 -0.597634
  0.382396
  0.297288
 -0.0104452

При необходимости можно выбрать алгоритм сортировки:

julia> sort(v, alg=InsertionSort)
5-element Array{Float64,1}:
 -0.839027
 -0.597634
 -0.0104452
  0.297288
  0.382396

Все функции, связанные с сортировкой и упорядочением, основаны на отношении «меньше, чем», определяющим общий порядок обрабатываемых значений. Функция isless вызывается по умолчанию, но отношение можно указать с помощью ключевого слова lt.

Функции сортировки

sort!(A; dims::Integer, alg::Algorithm=defalg(A), lt=isless, by=identity, rev::Bool=false, order::Ordering=Forward)

Сортировка многомерного массива A в измерении dims. Описание возможных именованных аргументов см. в разделе о sort!.

Сведения о сортировке срезов массива см. в разделе о sortslices.

Совместимость: Julia 1.1

Для этой функции требуется версия Julia не ниже 1.1.

Примеры

julia> A = [4 3; 1 2]
2×2 Matrix{Int64}:
 4  3
 1  2

julia> sort!(A, dims = 1); A
2×2 Matrix{Int64}:
 1  2
 4  3

julia> sort!(A, dims = 2); A
2×2 Matrix{Int64}:
 1  2
 3  4

sort!(A; dims::Integer, alg::Algorithm=defalg(A), lt=isless, by=identity, rev::Bool=false, order::Ordering=Forward)

Sort the multidimensional array A along dimension dims. See sort! for a description of possible keyword arguments.

To sort slices of an array, refer to sortslices.

Совместимость: Julia 1.1

This function requires at least Julia 1.1.

Examples

julia> A = [4 3; 1 2]
2×2 Matrix{Int64}:
 4  3
 1  2

julia> sort!(A, dims = 1); A
2×2 Matrix{Int64}:
 1  2
 4  3

julia> sort!(A, dims = 2); A
2×2 Matrix{Int64}:
 1  2
 3  4
sort(v; alg::Algorithm=defalg(v), lt=isless, by=identity, rev::Bool=false, order::Ordering=Forward)

Вариант sort!, который возвращает отсортированную копию v, оставляя v без изменений.

Примеры

julia> v = [3, 1, 2];

julia> sort(v)
3-element Vector{Int64}:
 1
 2
 3

julia> v
3-element Vector{Int64}:
 3
 1
 2

sort(A; dims::Integer, alg::Algorithm=defalg(A), lt=isless, by=identity, rev::Bool=false, order::Ordering=Forward)

Сортировка многомерного массива A в заданном измерении. См. раздел о sort! с описанием возможных именованных аргументов.

Сведения о сортировке срезов массива см. в разделе о sortslices.

Примеры

julia> A = [4 3; 1 2]
2×2 Matrix{Int64}:
 4  3
 1  2

julia> sort(A, dims = 1)
2×2 Matrix{Int64}:
 1  2
 4  3

julia> sort(A, dims = 2)
2×2 Matrix{Int64}:
 3  4
 1  2
sortperm(A; alg::Algorithm=DEFAULT_UNSTABLE, lt=isless, by=identity, rev::Bool=false, order::Ordering=Forward, [dims::Integer])

Возвращает вектор перестановки или массив I, который размещает A[I] в отсортированном порядке в заданном измерении. Если A имеет несколько измерений, необходимо указать именованный аргумент dims. Порядок задается с помощью тех же ключевых слов, что и для sort!. Перестановка гарантированно будет стабильной, даже если алгоритмы сортировки являются нестабильными. Это значит, что индексы равных элементов отображаются в порядке возрастания.

См. также sortperm!, partialsortperm, invperm, indexin. Сведения о сортировке срезов массива см. в разделе о sortslices.

Совместимость: Julia 1.9

Для метода, принимающего dims, требуется версия Julia не ниже 1.9.

Примеры

julia> v = [3, 1, 2];

julia> p = sortperm(v)
3-element Vector{Int64}:
 2
 3
 1

julia> v[p]
3-element Vector{Int64}:
 1
 2
 3

julia> A = [8 7; 5 6]
2×2 Matrix{Int64}:
 8  7
 5  6

julia> sortperm(A, dims = 1)
2×2 Matrix{Int64}:
 2  4
 1  3

julia> sortperm(A, dims = 2)
2×2 Matrix{Int64}:
 3  1
 2  4
InsertionSort

Использует алгоритм сортировки вставкой.

Сортировка вставками проходит по одному элементу коллекции за раз, вставляя каждый элемент в правильную отсортированную позицию в выходном векторе.

Характеристики:

  • стабильность: сохраняет порядок элементов, которые сравниваются как равные

(например, «a» и «A» при сортировке букв без учета регистра).

  • на месте в памяти.

  • квадратичная производительность в количестве подлежащих сортировке элементов:

хорошо подходит для небольших коллекций, но не должна использоваться для больших.

MergeSort

Указывает на то, что функция сортировки должна использовать алгоритм сортировки вставками. Сортировка слиянием делит коллекцию на подколлекции и многократно объединяет их, сортируя каждую подколлекцию на каждом этапе до тех пор, пока вся коллекция не будет перекомпонована в отсортированный вид.

Характеристики:

  • стабильность: сохраняет порядок элементов, которые равны с точки зрения порядка (например, "a" и "A" при сортировке букв, игнорирующей регистр).

  • не на месте в памяти.

  • «разделяй и властвуй»: стратегия сортировки.

  • хорошая производительность для больших коллекций, но, как правило, не настолько быстрая, как fast as QuickSort.

QuickSort

Указывает на то, что функция сортировки должна использовать алгоритм быстрой сортировки, который не является стабильным.

Характеристики:

  • нестабильность: не сохраняет порядок элементов, которые равны с точки зрения порядка (например, "a" и "A" при сортировке букв, игнорирующей регистр).

  • на месте в памяти.

  • «разделяй и властвуй»: стратегия сортировки, аналогичная MergeSort.

  • хорошая производительность для больших коллекций.

PartialQuickSort{T <: Union{Integer,OrdinalRange}}

Указывает на то, что функция сортировки должна использовать алгоритм частичной быстрой сортировки. Частичная быстрая сортировка возвращает наименьшие k-элементы, отсортированные от наименьшего к наибольшему. Поиск и сортировка выполняются с помощью QuickSort.

Характеристики:

  • нестабильность: не сохраняет порядок элементов, которые равны с точки зрения порядка (например, "a" и "A" при сортировке букв, игнорирующей регистр).

  • на месте в памяти.

  • «разделяй и властвуй»: стратегия сортировки, аналогичная MergeSort.

Обратите внимание, что PartialQuickSort(k) необязательно выполняет сортировку всего массива. Например,

julia> x = rand(100);

julia> k = 50:100;

julia> s1 = sort(x; alg=QuickSort);

julia> s2 = sort(x; alg=PartialQuickSort(k));

julia> map(issorted, (s1, s2))
(true, false)

julia> map(x->issorted(x[k]), (s1, s2))
(true, true)

julia> s1[k] == s2[k]
true
sortperm!(ix, A; alg::Algorithm=DEFAULT_UNSTABLE, lt=isless, by=identity, rev::Bool=false, order::Ordering=Forward, initialized::Bool=false, [dims::Integer])

Аналогична sortperm, но принимает предварительно выделенный вектор индекса или массив ix с теми же осями (axes), что и в A. Если initialized имеет значение false (по умолчанию), ix инициализируется, чтобы содержать значения LinearIndices(A).

Совместимость: Julia 1.9

Для метода, принимающего dims, требуется версия Julia не ниже 1.9.

Примеры

julia> v = [3, 1, 2]; p = zeros(Int, 3);

julia> sortperm!(p, v); p
3-element Vector{Int64}:
 2
 3
 1

julia> v[p]
3-element Vector{Int64}:
 1
 2
 3

julia> A = [8 7; 5 6]; p = zeros(Int,2, 2);

julia> sortperm!(p, A; dims=1); p
2×2 Matrix{Int64}:
 2  4
 1  3

julia> sortperm!(p, A; dims=2); p
2×2 Matrix{Int64}:
 3  1
 2  4
sortslices(A; dims, alg::Algorithm=DEFAULT_UNSTABLE, lt=isless, by=identity, rev::Bool=false, order::Ordering=Forward)

Сортировка срезов массива A. Обязательный именованный аргумент dims должен быть целым числом или кортежем целых чисел. Он указывает измерения, в которых сортируются срезы.

Например, если A является матрицей, dims=1 будет сортировать строки, dims=2 будет сортировать столбцы. Обратите внимание, что функция сравнения по умолчанию в одномерных срезах выполняет лексикографическую сортировку.

Сведения об остальных именованных аргументах см. в документации по sort!.

Примеры

julia> sortslices([7 3 5; -1 6 4; 9 -2 8], dims=1) # Сортировка строк
3×3 Matrix{Int64}:
 -1   6  4
  7   3  5
  9  -2  8

julia> sortslices([7 3 5; -1 6 4; 9 -2 8], dims=1, lt=(x,y)->isless(x[2],y[2]))
3×3 Matrix{Int64}:
  9  -2  8
  7   3  5
 -1   6  4

julia> sortslices([7 3 5; -1 6 4; 9 -2 8], dims=1, rev=true)
3×3 Matrix{Int64}:
  9  -2  8
  7   3  5
 -1   6  4

julia> sortslices([7 3 5; 6 -1 -4; 9 -2 8], dims=2) # Сортировка столбцов
3×3 Matrix{Int64}:
  3   5  7
 -1  -4  6
 -2   8  9

julia> sortslices([7 3 5; 6 -1 -4; 9 -2 8], dims=2, alg=InsertionSort, lt=(x,y)->isless(x[2],y[2]))
3×3 Matrix{Int64}:
  5   3  7
 -4  -1  6
  8  -2  9

julia> sortslices([7 3 5; 6 -1 -4; 9 -2 8], dims=2, rev=true)
3×3 Matrix{Int64}:
 7   5   3
 6  -4  -1
 9   8  -2

Более высокие измерения

sortslices естественным образом распространяется на более высокие измерения. Например, если A является массивом 2x2x2, sortslices(A, dims=3) будет сортировать срезы в третьем измерении, передавая срезы 2x2 A[:, :, 1] и A[:, :, 2] функции сравнения. Обратите внимание, что хотя для срезов более высоких измерений порядок по умолчанию отсутствует, его можно указать с помощью именованного аргумента by или lt.

Если dims представляет собой кортеж, порядок измерений в dims является относительным и указывает линейный порядок срезов. Например, если A является трехмерным и dims имеет значение (1, 2), порядки первых двух измерений изменяются таким образом, что сортируются срезы (оставшегося третьего измерения). Если dims имеет значение (2, 1), используются же самые срезы, но результирующий порядок будет построчным.

Примеры более высоких измерений

julia> A = permutedims(reshape([4 3; 2 1; 'A' 'B'; 'C' 'D'], (2, 2, 2)), (1, 3, 2))
2×2×2 Array{Any, 3}:
[:, :, 1] =
 4  3
 2  1

[:, :, 2] =
 'A'  'B'
 'C'  'D'

julia> sortslices(A, dims=(1,2))
2×2×2 Array{Any, 3}:
[:, :, 1] =
 1  3
 2  4

[:, :, 2] =
 'D'  'B'
 'C'  'A'

julia> sortslices(A, dims=(2,1))
2×2×2 Array{Any, 3}:
[:, :, 1] =
 1  2
 3  4

[:, :, 2] =
 'D'  'C'
 'B'  'A'

julia> sortslices(reshape([5; 4; 3; 2; 1], (1,1,5)), dims=3, by=x->x[1,1])
1×1×5 Array{Int64, 3}:
[:, :, 1] =
 1

[:, :, 2] =
 2

[:, :, 3] =
 3

[:, :, 4] =
 4

[:, :, 5] =
 5

Функции, связанные с упорядочением

issorted(v, lt=isless, by=identity, rev::Bool=false, order::Ordering=Forward)

Проверяет, находится ли вектор в отсортированном порядке. Ключевые слова lt, by и rev изменяют то, какой порядок считается отсортированным так, как они это делают для sort.

Примеры

julia> issorted([1, 2, 3])
true

julia> issorted([(1, "b"), (2, "a")], by = x -> x[1])
true

julia> issorted([(1, "b"), (2, "a")], by = x -> x[2])
false

julia> issorted([(1, "b"), (2, "a")], by = x -> x[2], rev=true)
true
searchsorted(a, x; by=<transform>, lt=<comparison>, rev=false)

Возвращает диапазон индексов a, которые сравниваются как равные x (с использованием двоичного поиска), в соответствии с порядком, заданным ключевыми словами by, lt и rev, и с предположением, что a уже отсортирован в этом порядке. Возвращает пустой диапазон, расположенный в точке вставки, если a не содержит значения, равные x.

См. также описание insorted, searchsortedfirst, sort, findall.

Примеры

julia> searchsorted([1, 2, 4, 5, 5, 7], 4) # одно совпадение
3:3

julia> searchsorted([1, 2, 4, 5, 5, 7], 5) # несколько совпадений
4:5

julia> searchsorted([1, 2, 4, 5, 5, 7], 3) # нет совпадений, вставить в середину
3:2

julia> searchsorted([1, 2, 4, 5, 5, 7], 9) # нет совпадений, вставить в конец
7:6

julia> searchsorted([1, 2, 4, 5, 5, 7], 0) # нет совпадений, вставить в начало
1:0
searchsortedfirst(a, x; by=<transform>, lt=<comparison>, rev=false)

Возвращает индекс первого значения в a, большего или равного x, в соответствии с указанным порядком. Возвращает lastindex(a) + 1, если x больше, чем все значения в a. a считается отсортированным.

Вставка (insert!) x по этому индексу будет поддерживать отсортированный порядок.

См. также описание searchsortedlast, searchsorted, findfirst.

Примеры

julia> searchsortedfirst([1, 2, 4, 5, 5, 7], 4) # одно совпадение
3

julia> searchsortedfirst([1, 2, 4, 5, 5, 7], 5) # несколько совпадений
4

julia> searchsortedfirst([1, 2, 4, 5, 5, 7], 3) # нет совпадений, вставить в середину
3

julia> searchsortedfirst([1, 2, 4, 5, 5, 7], 9) # нет совпадений, вставить в конец
7

julia> searchsortedfirst([1, 2, 4, 5, 5, 7], 0) # нет совпадений, вставить в начало
1
searchsortedlast(a, x; by=<transform>, lt=<comparison>, rev=false)

Возвращает индекс последнего значения в a, большего или равного x, в соответствии с указанным порядком. Возвращает firstindex(a) - 1, если x меньше чем все значения в a. a считается отсортированным.

Примеры

julia> searchsortedlast([1, 2, 4, 5, 5, 7], 4) # одно совпадение
3

julia> searchsortedlast([1, 2, 4, 5, 5, 7], 5) # несколько совпадений
5

julia> searchsortedlast([1, 2, 4, 5, 5, 7], 3) # нет совпадений, вставить в середину
2

julia> searchsortedlast([1, 2, 4, 5, 5, 7], 9) # нет совпадений, вставить в конец
6

julia> searchsortedlast([1, 2, 4, 5, 5, 7], 0) # нет совпадений, вставить в начало
0
insorted(x, a; by=<transform>, lt=<comparison>, rev=false) -> Bool

Определяет, находится ли элемент x в заданной отсортированной коллекции a в том смысле, что он == одному из значений коллекции в соответствии с порядком, заданным ключевыми словами by, lt и rev и с предположением, что a уже отсортирован в этом порядке. Сведения о ключевых словах см. в разделе о sort.

См. также описание in.

Примеры

julia> insorted(4, [1, 2, 4, 5, 5, 7]) # одно совпадение
true

julia> insorted(5, [1, 2, 4, 5, 5, 7]) # несколько совпадений
true

julia> insorted(3, [1, 2, 4, 5, 5, 7]) # нет совпадений
false

julia> insorted(9, [1, 2, 4, 5, 5, 7]) # нет совпадений
false

julia> insorted(0, [1, 2, 4, 5, 5, 7]) # нет совпадений
false
Совместимость: Julia 1.6

Функция insorted была добавлена в Julia 1.6.

partialsort!(v, k; by=<transform>, lt=<comparison>, rev=false)

Частичная сортировка вектора v на месте в соответствии с порядком, заданным by, lt и rev и с предположением, что значение по индексу k (или диапазон смежных значений, если k является диапазоном) появляется в позиции, где оно могло бы находиться, если бы массив был полностью отсортирован. Если k является одним индексом, возвращается это значение. Если k является диапазоном, возвращается массив значений по этим индексам. Обратите внимание, что partialsort! не выполняет полную сортировку входного массива.

Примеры

julia> a = [1, 2, 4, 3, 4]
5-element Vector{Int64}:
 1
 2
 4
 3
 4

julia> partialsort!(a, 4)
4

julia> a
5-element Vector{Int64}:
 1
 2
 3
 4
 4

julia> a = [1, 2, 4, 3, 4]
5-element Vector{Int64}:
 1
 2
 4
 3
 4

julia> partialsort!(a, 4, rev=true)
2

julia> a
5-element Vector{Int64}:
 4
 4
 3
 2
 1
partialsort(v, k, by=<transform>, lt=<comparison>, rev=false)

Вариант partialsort!, который копирует v до его частичной сортировки, тем самым возвращая то же, что и partialsort!, но не изменяя v.

partialsortperm(v, k; by=<transform>, lt=<comparison>, rev=false)

Возвращает частичную перестановку I вектора v, так что v[I] возвращает значения полностью отсортированной версии v в индексе k. Если k является диапазоном, возвращается вектор индексов. Если k является целым числом, возвращается один индекс. Порядок задается с помощью тех же ключевых слов, что и для sort!. Перестановка является стабильной. Это значит, что индексы равных элементов отображаются в порядке возрастания.

Обратите внимание, что эта функция эквивалентна вызову sortperm(...)[k], но является более эффективной.

Примеры

julia> v = [3, 1, 2, 1];

julia> v[partialsortperm(v, 1)]
1

julia> p = partialsortperm(v, 1:3)
3-element view(::Vector{Int64}, 1:3) with eltype Int64:
 2
 4
 3

julia> v[p]
3-element Vector{Int64}:
 1
 1
 2
partialsortperm!(ix, v, k; by=<transform>, lt=<comparison>, rev=false, initialized=false)

Аналогична partialsortperm, но принимает предварительно выделенный вектор индекса ix того же размера, что и у v, который используется для хранения (перестановки) индексов v.

Если вектор индекса ix инициализируется векторами v (или их перестановкой), initialized следует задать значение true.

Если initialized имеет значение false (по умолчанию), ix инициализируется, чтобы содержать индексы v.

Если initialized имеет значение true, но ix не содержит (перестановку) индексов v, поведение partialsortperm! является неопределенным.

(Обычно индексы v будут иметь значение 1:length(v), хотя если v имеет альтернативный тип массива с индексами на основе, отличной от единицы, такой как OffsetArray, ix также должен быть OffsetArray с теми же индексами и должен содержать в качестве значений (перестановку) те же индексы.)

После возвращения ix гарантированно будет иметь индексы k в отсортированных позициях, как показано далее.

partialsortperm!(ix, v, k);
v[ix[k]] == partialsort(v, k)

Возвращаемым значением является k-й элемент вектора индекса ix, если k представляет собой целое число, или представлением ix, если k представляет собой диапазон.

Примеры

julia> v = [3, 1, 2, 1];

julia> ix = Vector{Int}(undef, 4);

julia> partialsortperm!(ix, v, 1)
2

julia> ix = [1:4;];

julia> partialsortperm!(ix, v, 2:3, initialized=true)
2-element view(::Vector{Int64}, 2:3) with eltype Int64:
 4
 3

Алгоритмы сортировки

В настоящее время в базовой версии Julia общедоступны четыре алгоритма сортировки:

По умолчанию семейство функций sort использует стабильные алгоритмы сортировки, которые быстро работают с большинством входных данных. Точный выбор алгоритма является особенностью реализации, позволяющей улучшить производительность в будущем. В настоящее время в зависимости от типа, размера и состава входных данных используется гибрид RadixSort, ScratchQuickSort, InsertionSort и CountingSort. Детали реализации могут меняться, но сейчас они доступны в расширенной справке по ??Base.DEFAULT_STABLE и указанных там docstrings внутренних алгоритмов сортировки.

Вы можете явным образом указать предпочитаемый алгоритм с помощью ключевого слова alg (например, sort!(v, alg=PartialQuickSort(10:20))) или перенастроить алгоритм сортировки по умолчанию для пользовательских типов, добавив специализированный метод в функцию Base.Sort.defalg. Например, InlineStrings.jl определяет следующий метод:

Base.Sort.defalg(::AbstractArray{<:Union{SmallInlineStrings, Missing}}) = InlineStringSort
Совместимость: Julia 1.9

Алгоритм сортировки по умолчанию (возвращаемый Base.Sort.defalg) гарантированно стабилен начиная с Julia 1.9. Предыдущие версии имели нестабильные пограничные случаи при сортировке числовых массивов.

Альтернативные упорядочения

По умолчанию sort и связанные функции используют isless для сравнения двух элементов, чтобы определить, какой из них должен быть первым. Абстрактный тип Base.Order.Ordering предоставляет механизм для определения альтернативных упорядочений для одного и того же набора элементов. Экземпляры Ordering определяют общий порядок для набора элементов, так что для любых элементов a, b, c выполняются следующие условия.

  • Верно только одно из следующих утверждений: a меньше b, b меньше a, или a и b равны (в соответствии с isequal).

  • Отношение является транзитивным — если a меньше b и b меньше c , то a меньше c.

Функция Base.Order.lt работает как обобщение isless для проверки того, является ли a меньше b в соответствии с заданным порядком.

Base.Order.Ordering

Абстрактный тип, представляющий общий порядок в некотором наборе элементов.

Используйте Base.Order.lt для сравнения двух элементов в соответствии с упорядочением.

lt(o::Ordering, a, b)

Проверяет, меньше ли a, чем b, в соответствии с упорядочением o.

ord(lt, by, rev::Union{Bool, Nothing}, order::Ordering=Forward)

Создает объект Ordering на основе тех же аргументов, которые использует функция sort!. Сначала элементы преобразуются с помощью функции by (это может быть identity), а затем сравниваются в соответствии с функцией lt или существующем упорядочением order. lt должен иметь значение isless или быть функцией, для которой действуют аналогичные правила. И, наконец, результирующий порядок меняется на обратный, если rev=true.

Передача lt, отличного от isless, вместе с order, отличным от Base.Order.Forward или Base.Order.Reverse, запрещена. В противном случае все параметры независимы и могут использоваться вместе во всех возможных комбинациях.

Base.Order.Forward

Порядок по умолчанию в соответствии с isless.

ReverseOrdering(fwd::Ordering=Forward)

Оболочка, которая меняет порядок на обратный.

Для заданного Ordering o следующее справедливо для всех a, b:

lt(ReverseOrdering(o), a, b) == lt(o, b, a)
Base.Order.Reverse

Меняет порядок на обратный в соответствии с isless.

By(by, order::Ordering=Forward)

Ordering, который применяет order к элементам после их преобразования функцией by.

Lt(lt)

Ordering, который вызывает lt(a, b) для сравнения элементов. lt должен следовать тем же правилам, которые действуют для реализаций isless.

Perm(order::Ordering, data::AbstractVector)

Ordering в индексах data, где i меньше, чем j, если data[i] меньше, чем data[j], в соответствии с order. Если data[i] и data[j] равны, i и j сравниваются по числовому значению.