裏 RjpWiki

Julia ときどき R, Python によるコンピュータプログラム,コンピュータ・サイエンス,統計学

Julia の小ネタ--037 大小順や辞書順などではない,特別な順序に基づくソート

2021年09月16日 | ブログラミング

sort!() や sort() において,昇順とか降順は数値の大小とか文字列ならば辞書順(これも大小ではあるが)による。
しかし,ある場合には単なる辞書順ではなく別の基準で並べ替えなければならないことがある。
このような場合には,sort!() や sort() の引数の lt で関数を指定する。
その関数は引数を 2 つとり,a が b より前(昇順で b は a より後)ならば true,そうでなければ false を返す。デフォルトでは lt = isless である。isless も 2 つの引数をとり,例示するような結果を返す。

isless(1, 4) # true
isless("a", "abcde") # true
isless(π, ℯ) # π = 3.1415926535897...,ℯ = 2.7182818284590... ゆえ false

たとえば,年号が

nengou = ["明治", "大正", "昭和", "平成", "令和"]

のとき,普通にソートすると

sort(nengou)

#=
5-element Vector{String}:
 "令和"
 "大正"
 "平成"
 "明治"
 "昭和"
=#

になってしまう。

年号のデータを「"明治", "大正", "昭和", "平成", "令和"」の順でソートしたいときは以下のような関数を定義する。

function compare(a, b)
    rank(nengou) = indexin([nengou], ["明治", "大正", "昭和", "平成", "令和"])[1]
    return rank(a) <= rank(b)
end

そのうえで,

sort(nengou, lt=compare)

とすれば,以下の結果になる。

#=
5-element Vector{String}:
 "明治"
 "大正"
 "昭和"
 "平成"
 "令和"
=#

これは別に Julia だからということではなく,R でも Python でもそのような関数仕様になっている。

x = ["平成3", "令和2","大正7", "昭和6", "明治2", "令和1", "昭和9"]

のようなデータを年号と年の順に並べ替えるには,以下のような関数を使う。
年号を100の位,年を10, 1 の位に割り当てて一つの整数にして,大小関係を判定する関数である。
なお,データは UTF-8 なので,漢字の場合には文字数と桁数が異なるので注意が必要ではある。

function compare2(a, b)
    rank(nengou) = 100indexin([nengou[1:4]], ["明治", "大正", "昭和", "平成", "令和"])[1] + parse(Int, nengou[7:end])
    return rank(a) <= rank(b)
end

rank("明治23") # 123
rank("昭和5")  # 305

sort(x, lt=compare2)
#=
7-element Vector{String}:
 "明治2"
 "大正7"
 "昭和6"
 "昭和9"
 "平成3"
 "令和1"
 "令和2"
=#

コメント
  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする

Julia の小ネタ--036 文字が文字列に含まれるか?

2021年09月16日 | ブログラミング

多くの言語では,1 文字が文字列中にあるかどうかは簡単な関数で調べることができる。

たとえば,Python なら

"abcdefg".find("c")   # 2
"abcdefg".find("z")   # -1 存在しない場合

Julia では,

occursin("c", "abcdefg")   # true
occursin("xyz", "abcdefg") # false

Julia の indexin(a, b) は a が b に含まれないときには nothing を返すという,ありがたいんだかありがたくないんだか,微妙な仕様になっている。

そこで,以下のような find 関数を実装してみた。

indexin() の a, b は配列でもよいのだけど,find() の第1引数は 文字型(Char)もしくは長さ1の文字列,第2引数は文字列または整数に限定する。引数の組み合わせとして4通りあるので,find() も 4 通り書き,最終的に5番目に定義する関数が呼ばれる。5番目の関数の第1引数は Char型,第2引数は Vector{Char} である。indexin() を呼び,結果が nothing のときには 0 を返すようにしている。

find(c::Char,   n::Int)     = find(c, string(n))
find(c::Char,   s::String)  = find(c, Char[s...])
find(s::String, n::Int)     = find(Char(s...), string(n))
find(s::String, ss::String) = find(Char(s...), Char[ss...])
function find(c::Char, cc::Vector{Char})
    x = indexin(c, cc)[1]
    isnothing.(x) ? 0 : x
end

この関数群がどのように働くかは実行例を見れば一目瞭然。

find('3', 123)   # 3
find('4', 123)   # 0
find('3', "123") # 3
find('4', "123") # 0
find("3", 123)   # 3
find("4", 123)   # 0
find("3", "123") # 3
find("4", "123") # 0

 

コメント
  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする

PVアクセスランキング にほんブログ村

PVアクセスランキング にほんブログ村