Sorting and Related Functions
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
すべてのソートおよび順序関連の関数は、操作される値に対して「小なり」関係を定義する strict weak order に依存しています。デフォルトでは isless
関数が呼び出されますが、関係は lt
キーワードを介して指定できます。これは、2つの配列要素を受け取り、最初の引数が2番目の引数よりも「小さい」場合にのみ true
を返す関数です。詳細については、sort!
および Alternate Orderings を参照してください。
Sorting Functions
Base.sort!
— Functionsort!(v; alg::Algorithm=defalg(v), lt=isless, by=identity, rev::Bool=false, order::Ordering=Forward)
ベクター v
をその場でソートします。デフォルトでは安定したアルゴリズムが使用されます:等しいと比較される要素の順序は保持されます。特定のアルゴリズムは alg
キーワードを介して選択できます(利用可能なアルゴリズムについては Sorting Algorithms を参照してください)。
要素は最初に by
関数で変換され、その後 lt
関数または order
に従って比較されます。最後に、rev=true
の場合は結果の順序が逆転されます(これにより前方の安定性が保持されます:等しいと比較される要素は逆転されません)。現在の実装では、各比較の前に by
変換が適用され、要素ごとに一度だけではありません。
isless
以外の lt
を Base.Order.Forward
(@ref) または Base.Order.Reverse
(@ref) 以外の order
と一緒に渡すことは許可されていません。それ以外はすべてのオプションは独立しており、すべての可能な組み合わせで一緒に使用できます。order
は "by" 変換を含むこともでき、その場合は by
キーワードで定義された後に適用されます。order
値に関する詳細は Alternate Orderings のドキュメントを参照してください。
2つの要素間の関係は次のように定義されます(rev=true
の場合は「小さい」と「大きい」が交換されます):
x
はy
より小さい場合、lt(by(x), by(y))
(またはBase.Order.lt(order, by(x), by(y))
)が真を返します。x
はy
より大きい場合、y
がx
より小さいです。x
とy
は互いに小さくない場合、等価です(「比較不能」は「等価」の同義語として時々使用されます)。
sort!
の結果は、すべての要素が前の要素より大きいか等価であるという意味でソートされています。
lt
関数は厳密な弱順序を定義する必要があります。つまり、次の条件を満たさなければなりません:
- 反射的でない:
lt(x, x)
は常にfalse
を返す。 - 非対称:
lt(x, y)
が真を返す場合、lt(y, x)
は偽を返す。 - 推移的:
lt(x, y) && lt(y, z)
はlt(x, z)
を含意する。 - 等価における推移的:
!lt(x, y) && !lt(y, x)
と!lt(y, z) && !lt(z, y)
が一緒にある場合、!lt(x, z) && !lt(z, x)
を含意する。言い換えれば:x
とy
が等価であり、y
とz
が等価である場合、x
とz
も等価でなければなりません。
例えば、<
は Int
値に対する有効な lt
関数ですが、≤
は無効です:反射性を侵害します。Float64
値の場合、<
でさえ無効です。なぜなら、4番目の条件を侵害するからです:1.0
と NaN
は等価であり、NaN
と 2.0
も等価ですが、1.0
と 2.0
は等価ではありません。
他にも sort
、sortperm
、sortslices
、partialsort!
、partialsortperm
、issorted
、searchsorted
、insorted
、Base.Order.ord
を参照してください。
例
julia> v = [3, 1, 2]; sort!(v); v
3-element Vector{Int64}:
1
2
3
julia> v = [3, 1, 2]; sort!(v, rev = true); v
3-element Vector{Int64}:
3
2
1
julia> v = [(1, "c"), (3, "a"), (2, "b")]; sort!(v, by = x -> x[1]); v
3-element Vector{Tuple{Int64, String}}:
(1, "c")
(2, "b")
(3, "a")
julia> v = [(1, "c"), (3, "a"), (2, "b")]; sort!(v, by = x -> x[2]); v
3-element Vector{Tuple{Int64, String}}:
(3, "a")
(2, "b")
(1, "c")
julia> sort(0:3, by=x->x-2, order=Base.Order.By(abs)) # same as sort(0:3, by=abs(x->x-2))
4-element Vector{Int64}:
2
1
3
0
julia> sort([2, NaN, 1, NaN, 3]) # correct sort with default lt=isless
5-element Vector{Float64}:
1.0
2.0
3.0
NaN
NaN
julia> sort([2, NaN, 1, NaN, 3], lt=<) # wrong sort due to invalid lt. This behavior is undefined.
5-element Vector{Float64}:
2.0
NaN
1.0
NaN
3.0
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> 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
Base.sort
— Functionsort(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
Base.sortperm
— Functionsortperm(A; alg::Algorithm=DEFAULT_UNSTABLE, lt=isless, by=identity, rev::Bool=false, order::Ordering=Forward, [dims::Integer])
配列 A
を与えられた次元でソートされた順序にするための置換ベクトルまたは配列 I
を返します。A
が複数の次元を持つ場合、dims
キーワード引数を指定する必要があります。順序は sort!
と同じキーワードを使用して指定されます。置換は、ソートアルゴリズムが不安定であっても安定であることが保証されており、等しい要素のインデックスは昇順で表示されます。
他に sortperm!
、partialsortperm
、invperm
、indexin
も参照してください。配列のスライスをソートするには、sortslices
を参照してください。
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
Base.Sort.InsertionSort
— Constant挿入ソート
挿入ソートアルゴリズムを使用します。
挿入ソートは、コレクションを1つの要素ずつ走査し、各要素を出力ベクターの正しいソートされた位置に挿入します。
特徴:
- 安定性: 等しいと比較される要素の順序を保持します
(例: 大文字と小文字を無視した文字のソートにおける "a" と "A")。
- メモリ内でのインプレース。
- 二次性能:ソートされる要素の数に対して:
小さなコレクションには適していますが、大きなコレクションには使用すべきではありません。
Base.Sort.MergeSort
— Constantマージソート
ソート関数がマージソートアルゴリズムを使用することを示します。マージソートはコレクションをサブコレクションに分割し、それらを繰り返しマージし、各ステップで各サブコレクションをソートし、最終的に全体のコレクションがソートされた形で再結合されるまで続けます。
特徴:
- 安定: 等しいと比較される要素の順序を保持します(例: 大文字と小文字を無視した文字のソートにおける "a" と "A")。
- メモリ内でのインプレースではない。
- 分割統治ソート戦略。
- 大規模コレクションに対して良好なパフォーマンスを発揮しますが、通常は
クイックソート
ほど速くはありません。
Base.Sort.QuickSort
— Constantクイックソート
ソート関数はクイックソートアルゴリズムを使用する必要があり、これは安定ではありません。
特徴:
- 安定ではない: 等しいと比較される要素の順序を保持しません(例:"a"と"A"が大文字と小文字を無視した文字のソートで)。
- インプレースでメモリ内。
- 分割統治法:
マージソート
に似たソート戦略。 - 大規模コレクションに対して良好なパフォーマンス。
Base.Sort.PartialQuickSort
— TypePartialQuickSort{T <: Union{Integer,OrdinalRange}}
ソート関数は部分クイックソートアルゴリズムを使用する必要があることを示します。PartialQuickSort(k)
はQuickSort
のようなもので、v
が完全にソートされている場合にv[k]
に配置される要素を見つけてソートすることだけが求められます。
特徴:
- 安定ではない: 同じ値を比較する要素の順序を保持しません(例: 大文字と小文字を無視した文字のソートにおける "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
Base.Sort.sortperm!
— Functionsortperm!(ix, A; alg::Algorithm=DEFAULT_UNSTABLE, lt=isless, by=identity, rev::Bool=false, order::Ordering=Forward, [dims::Integer])
sortperm
と同様ですが、A
と同じaxes
を持つ事前に割り当てられたインデックスベクトルまたは配列ix
を受け入れます。ix
はLinearIndices(A)
の値を含むように初期化されます。
変更された引数が他の引数とメモリを共有している場合、動作が予期しないものになることがあります。
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
Base.sortslices
— Functionsortslices(A; dims, alg::Algorithm=DEFAULT_UNSTABLE, lt=isless, by=identity, rev::Bool=false, order::Ordering=Forward)
配列 A
のスライスをソートします。必須のキーワード引数 dims
は整数または整数のタプルでなければなりません。これは、スライスがソートされる次元を指定します。
例えば、A
が行列の場合、dims=1
は行をソートし、dims=2
は列をソートします。1次元スライスのデフォルトの比較関数は辞書式にソートされることに注意してください。
残りのキーワード引数については、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)
は3次元内のスライスをソートし、2x2 のスライス A[:, :, 1]
と A[:, :, 2]
を比較関数に渡します。高次元スライスにはデフォルトの順序はありませんが、by
または lt
のキーワード引数を使用してそのような順序を指定できます。
dims
がタプルの場合、dims
内の次元の順序は重要であり、スライスの線形順序を指定します。例えば、A
が三次元で dims
が (1, 2)
の場合、最初の2つの次元の順序が再配置され、残りの3次元のスライスがソートされます。代わりに dims
が (2, 1)
の場合、同じスライスが取得されますが、結果の順序は行優先になります。
高次元の例
julia> A = [4 3; 2 1 ;;; 'A' 'B'; 'C' 'D']
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
Order-Related Functions
Base.issorted
— Functionissorted(v, lt=isless, by=identity, rev::Bool=false, order::Ordering=Forward)
コレクションがソートされた順序にあるかどうかをテストします。キーワードは、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
julia> issorted([1, 2, -2, 3], by=abs)
true
Base.Sort.searchsorted
— Functionsearchsorted(v, x; by=identity, lt=isless, rev=false)
v
内の値がx
と等しいインデックスの範囲を返します。v
にx
と等しい値が含まれていない場合は、挿入位置にある空の範囲を返します。ベクトルv
は、キーワードで定義された順序に従ってソートされている必要があります。キーワードの意味と同値の定義については、sort!
を参照してください。by
関数は、検索される値x
とv
内の値の両方に適用されます。
範囲は一般的に二分探索を使用して見つけられますが、一部の入力に対しては最適化された実装があります。
関連情報: searchsortedfirst
, sort!
, insorted
, 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
julia> searchsorted([1=>"one", 2=>"two", 2=>"two", 4=>"four"], 2=>"two", by=first) # ペアのキーを比較
2:3
Base.Sort.searchsortedfirst
— Functionsearchsortedfirst(v, x; by=identity, lt=isless, rev=false)
x
よりも前に順序付けられていないv
の最初の値のインデックスを返します。もしv
のすべての値がx
の前に順序付けられている場合、lastindex(v) + 1
を返します。
ベクトルv
は、キーワードで定義された順序に従ってソートされている必要があります。返されたインデックスでx
をinsert!
すると、ソートされた順序が維持されます。キーワードの意味と使用法については、sort!
を参照してください。by
関数は、検索される値x
とv
の値の両方に適用されることに注意してください。
インデックスは一般的に二分探索を使用して見つけられますが、一部の入力に対しては最適化された実装があります。
関連情報: 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
julia> searchsortedfirst([1=>"one", 2=>"two", 4=>"four"], 3=>"three", by=first) # ペアのキーを比較
3
Base.Sort.searchsortedlast
— Functionsearchsortedlast(v, x; by=identity, lt=isless, rev=false)
v
の中でx
の後に順序付けされていない最後の値のインデックスを返します。もしv
のすべての値がx
の後に順序付けされている場合、firstindex(v) - 1
を返します。
ベクトルv
は、キーワードによって定義された順序に従ってソートされている必要があります。返されたインデックスのすぐ後にx
をinsert!
すると、ソートされた順序が維持されます。キーワードの意味と使用法についてはsort!
を参照してください。by
関数は、検索される値x
とv
の値の両方に適用されることに注意してください。
インデックスは一般的に二分探索を使用して見つけられますが、一部の入力に対しては最適化された実装があります。
例
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
julia> searchsortedlast([1=>"one", 2=>"two", 4=>"four"], 3=>"three", by=first) # ペアのキーを比較
2
Base.Sort.insorted
— Functioninsorted(x, v; by=identity, lt=isless, rev=false) -> Bool
ベクトル v
に x
と等価な値が含まれているかどうかを判断します。ベクトル v
はキーワードで定義された順序に従ってソートされている必要があります。キーワードの意味や等価性の定義については sort!
を参照してください。by
関数は、検索される値 x
と v
の値の両方に適用されます。
チェックは一般的に二分探索を使用して行われますが、一部の入力に対しては最適化された実装があります。
さらに 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> insorted(2=>"TWO", [1=>"one", 2=>"two", 4=>"four"], by=first) # ペアのキーを比較
true
insorted
は Julia 1.6 で追加されました。
Base.Sort.partialsort!
— Functionpartialsort!(v, k; by=identity, lt=isless, rev=false)
ベクトル v
を部分的にソートし、インデックス k
(または k
が範囲の場合は隣接する値の範囲)の位置に、その値が完全にソートされた場合に出現する位置に配置します。k
が単一のインデックスの場合、その値が返されます。k
が範囲の場合、そのインデックスにある値の配列が返されます。partialsort!
は入力配列を完全にソートしない場合があることに注意してください。
キーワード引数については、sort!
のドキュメントを参照してください。
例
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
Base.Sort.partialsort
— Functionpartialsort(v, k, by=identity, lt=isless, rev=false)
partialsort!
のバリアントで、部分的にソートする前に v
をコピーし、partialsort!
と同じものを返しますが、v
は変更されません。
Base.Sort.partialsortperm
— Functionpartialsortperm(v, k; by=identity, lt=isless, rev=false)
ベクトル v
の部分的な順列 I
を返します。これにより、v[I]
はインデックス k
における v
の完全にソートされたバージョンの値を返します。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
Base.Sort.partialsortperm!
— Functionpartialsortperm!(ix, v, k; by=identity, lt=isless, rev=false)
partialsortperm
と同様ですが、v
と同じサイズの事前に割り当てられたインデックスベクトルix
を受け入れ、v
のインデックスの(順列の)格納に使用されます。
ix
はv
のインデックスを含むように初期化されます。
(通常、v
のインデックスは1:length(v)
ですが、v
がOffsetArray
のような非1ベースのインデックスを持つ代替配列型である場合、ix
はそれらの同じインデックスを共有しなければなりません)
戻り値として、ix
はk
のインデックスがソートされた位置にあることが保証されており、次のようになります。
partialsortperm!(ix, v, k);
v[ix[k]] == partialsort(v, k)
戻り値は、k
が整数の場合はix
のk
番目の要素、k
が範囲の場合はix
へのビューです。
変更された引数が他の引数とメモリを共有している場合、動作が予期しないものになることがあります。
例
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)
2-element view(::Vector{Int64}, 2:3) with eltype Int64:
4
3
```
Sorting Algorithms
現在、ベースのJuliaには公開されている4つのソートアルゴリズムがあります:
デフォルトでは、sort
ファミリーの関数は、ほとんどの入力に対して高速な安定ソートアルゴリズムを使用します。正確なアルゴリズムの選択は、将来のパフォーマンス向上を可能にするための実装の詳細です。現在、入力の種類、サイズ、および構成に基づいて、RadixSort
、ScratchQuickSort
、InsertionSort
、およびCountingSort
のハイブリッドが使用されています。実装の詳細は変更される可能性がありますが、現在は??Base.DEFAULT_STABLE
の拡張ヘルプおよびそこにリストされている内部ソートアルゴリズムのドックストリングで利用可能です。
alg
キーワードを使用して、好みのアルゴリズムを明示的に指定できます(例: sort!(v, alg=PartialQuickSort(10:20))
)。また、カスタムタイプのデフォルトのソートアルゴリズムを再構成するには、Base.Sort.defalg
関数に特化したメソッドを追加します。例えば、InlineStrings.jl は次のメソッドを定義します:
Base.Sort.defalg(::AbstractArray{<:Union{SmallInlineStrings, Missing}}) = InlineStringSort
デフォルトのソートアルゴリズム(Base.Sort.defalg
によって返される)は、Julia 1.9以降、安定であることが保証されています。以前のバージョンでは、数値配列をソートする際に不安定なエッジケースがありました。
Alternate Orderings
デフォルトでは、sort
、searchsorted
、および関連する関数は、isless
を使用して2つの要素を比較し、どちらが先に来るべきかを判断します。Base.Order.Ordering
抽象型は、同じ要素のセットに対して代替の順序を定義するためのメカニズムを提供します。sort!
のようなソート関数を呼び出す際に、Ordering
のインスタンスをキーワード引数order
と共に提供することができます。
Ordering
のインスタンスは、Base.Order.lt
関数を通じて順序を定義します。この関数は、isless
の一般化として機能します。カスタムOrdering
に対するこの関数の動作は、strict weak orderのすべての条件を満たさなければなりません。詳細と有効および無効なlt
関数の例については、sort!
を参照してください。
Base.Order.Ordering
— TypeBase.Order.Ordering
抽象型で、いくつかの要素の集合に対する厳密な弱順序を表します。詳細についてはsort!
を参照してください。
Base.Order.lt
を使用して、順序に従って2つの要素を比較します。
Base.Order.lt
— Functionlt(o::Ordering, a, b) -> Bool
a
がb
よりもo
に従って小さいかどうかをテストします。
Base.Order.ord
— Functionord(lt, by, rev::Union{Bool, Nothing}, order::Ordering=Forward)
同じ引数を使用してsort!
オブジェクトからOrdering
オブジェクトを構築します。要素は最初に関数by
(これはidentity
である可能性があります)によって変換され、その後、関数lt
または既存の順序order
に従って比較されます。lt
はisless
であるか、sort!
のlt
パラメータと同じルールに従う関数である必要があります。最後に、rev=true
の場合、結果の順序は逆になります。
isless
以外のlt
をBase.Order.Forward
またはBase.Order.Reverse
以外のorder
と一緒に渡すことは許可されていません。それ以外は、すべてのオプションは独立しており、すべての可能な組み合わせで一緒に使用できます。
Base.Order.Forward
— ConstantBase.Order.Forward
デフォルトの順序はisless
に従います。
Base.Order.ReverseOrdering
— TypeReverseOrdering(fwd::Ordering=Forward)
順序を逆にするラッパーです。
与えられた Ordering
o
に対して、すべての a
、b
に対して以下が成り立ちます:
lt(ReverseOrdering(o), a, b) == lt(o, b, a)
Base.Order.Reverse
— ConstantBase.Order.Reverse
isless
に従った逆順序付け。
Base.Order.By
— TypeBy(by, order::Ordering=Forward)
Ordering
は、要素が関数by
によって変換された後にorder
を適用します。
Base.Order.Lt
— TypeLt(lt)
Ordering
は lt(a, b)
を呼び出して要素を比較します。lt
は sort!
の lt
パラメータと同じルールに従わなければなりません。
Base.Order.Perm
— TypePerm(order::Ordering, data::AbstractVector)
Ordering
はdata
のインデックスに対して、data[i]
がdata[j]
より小さい場合にi
がj
より小さいとします。data[i]
とdata[j]
が等しい場合は、i
とj
は数値で比較されます。