df2 = df.groupby(群)
df2.agg(自作関数の名前)
以下のようなプログラムがあった。
このプログラムだと,10**8 以下の素数を探索するのに 18 日くらいかかる。
import time
primes_list = []
upper_lim = 10**3
start_time = time.time()
for integer in range(2, upper_lim + 1, 1):
if len(primes_list) < 1 :
primes_list.append(integer)
else:
is_divisible = False
for prime in primes_list:
if integer % prime == 0:
is_divisible = True
break
if not is_divisible:
primes_list.append(integer)
#print(primes_list)
print(len(primes_list), "prime numbers foud.")
elapsed_time = time.time() - start_time # 経過時間 = 現在時刻 - 開始時刻
print ("run time: {0}".format(elapsed_time) + " seconds")
偶数の素数は 2 だけ。それ以外は奇数。range(2, upper_lim + 1, 1) でぶん回すのは少なくとも2倍の時間が掛かる。
for ループの中に len(primes_list) < 1 を毎回判定する if ブロックは無駄。
is_divisible という変数を使っているが,後で not is_divisible として使っているのなら,is_prime という変数を作ったほうがわかりやすい。
ある数が,primes_list の中にある素数で割りきれるか primes_list の全体を走査しているが,その数の平方根以下の要素まで調べればよい。そこまでで割り切れなければ素数。
Python の癖であるが,関数にしたほうが速い。
++++++++++
他の人からアドバイスがあって,書き直されたプログラムが3とおりあった。
関数化したこと
2 を特別に扱い,range(3, upper_limit + 1, 2) で探索すること。
all(integer % prime != 0 for prime in primes_list) を使うこと。
しかし,これはあまりよい提案ではないことがわかる。
素数かどうかの走査を早めに終えるためにはこの方法はよくない。
def primes_up_to_(upper_limit):
if upper_limit < 2:
return []
primes_list = [2]
for integer in range(3, upper_limit + 1, 2):
if all(integer % prime != 0 for prime in primes_list):
primes_list.append(integer)
return primes_list
++++++++++
もう一つのバージョン
for integer in range(2, upper_lim + 1, 1):
if len(primes_list) < 1 :
primes_list.append(integer)
else:
is_divisible = False
for prime in primes_list:
# if prime >= math.sqrt(integer): # このやり方は実によい!!
if prime > math.sqrt(integer): # 但し,> でないと間違い
break
elif integer % prime == 0:
is_divisible = True
break
if not is_divisible:
primes_list.append(integer)
++++++++++
もう一つのバージョンだが,何をやっているか理解しておらず,処理の重複のため長時間かかることになってしまった。
追加したものは if all() と重複する余分なもの。百害あって一利なし。それに,前のバージョンの prime > math.sqrt(integer) がなくなってしまった。
def primes_up_to_3(upper_limit): # 関数化
if upper_limit < 2:
return []
primes_list = [2]
for integer in range(3, upper_limit + 1, 2):
temp_primes_list = [] # 追加
for prime in primes_list: # 追加
if prime <= math.sqrt(integer): # 追加
temp_primes_list.append(prime) # 追加
if all(integer % prime != 0 for prime in temp_primes_list):
primes_list.append(integer)
return primes_list
++++++++++
私が考えていたバージョン。
def gen_primes2(upper_lim = 10000):
primes_list = [2]
for integer in range(3, upper_lim + 1, 2):
is_prime = True
upper_lim_sqrt = int(integer**0.5)
for prime in primes_list:
if prime > upper_lim_sqrt: # 時短にかなり有効
break
elif integer % prime == 0:
is_prime = False
break
if is_prime:
primes_list.append(integer)
return primes_list
これだと,最初のバージョンでは 10**8 までの検索に 18 日かかっていたであろうものが,10 分で終わる。
++++++++++
しかし,以下の Julia で書いたプログラムだと,さらにその 10 倍速い。
function gen_primes2(upper_lim = 10000)
primes_list = [2]
for integer = 3:2:upper_lim
upper_lim_sqrt = ceil(sqrt(integer))
is_prime = true
for prime in primes_list
if prime > upper_lim_sqrt
break
elseif integer % prime == 0
is_prime = false
break
end
end
if is_prime
append!(primes_list, integer)
end
end
println("$(length(primes_list)) prime numbers foud.")
# println(primes_list)
end
@time gen_primes2(10^8)
# $ julia gen_primes2.jl
# 5761455 prime numbers foud.
# 54.732656 seconds (35 allocations: 65.001 MiB, 0.00% gc time)
10**8 までの検索が 1分で終わる。
つまり,元のプログラムの2万6千倍速いのだ。
The Julia Language を読み進めているが,1300ページもあるので,モチベーションを維持するために,実際にプログラムも書いてみなくては。
julia> #=
他の言語と違うところに注目してまとめてみよう。
複数行の注釈は #= ... =#
形式としては Java などの /* ... */
=#
julia> println("我が輩は猫である。\n名前は", "まだない。")
我が輩は猫である。
名前はまだない。
文字列はダブルクオート '"' でなければならない。シングルクオート "'" だとエラーになる。
出力後改行するには print() ではなく println() を使う。これも Java などと同じ。print() で行末に '\n' を付けてもいいけど。
Python の print() とは違い,出力項目の間に自動的に空白は入らない。
julia> print('A', '1', 'π', '\n')
A1π
シングルクオートでくくるのは文字である。'\n' も改行を表す 1 文字。
'π' などのギリシア文字,特殊文字は '\pi[tab]' で入力できる( [tab]はタブキーを押す)。
julia> println("2^5 = $(2^5)")
2^5 = 32
羃乗は '^'。Python が '**' なのは,ちょっと異端なのだ。
"2^5 = $(2^5)" は 文字列中に式の結果を展開する記法。Python の print(f"2^5 = {2^5}") に相当する。
julia> println("整数除算: div(21, 4) = $(div(21, 4)) または 21 ÷ 4 = $(21 ÷ 4)\n",
" ÷ は \\div で入力する。\n",
" // は 分数形式(有理数)になる。Python と違うので要注意。\n",
" 21 // 4 = $(21 // 4), float(21 // 4) = $(float(21 // 4))\n",
" 240 // 36 = $(240 // 36)")
整数除算: div(21, 4) = 5 または 21 ÷ 4 = 5
÷ は \div で入力する。
// は 分数形式(有理数)になる。Python と違うので要注意。
21 // 4 = 21//4, float(21 // 4) = 5.25
240 // 36 = 20//3
整数剰余: mod(21, 4) = 1 または rem(21, 4) = 1 または 21 % 4 = 1
しかし,除数,被除数に符号が付くと,ややこしいことになる。
整数 a, b に対する除算の結果の「商」と「余り」について「商*b + 剰余 = a」という等式が成り立つことが規定されている。
3 つの関数を定義して,この等式が成り立つかどうかをチェックしてみよう。結果の表示は 「a, b, 商,剰余,等式が成り立つかどうか」の順である。
julia> h(a, b) = println("div() and mod(): $a, $b, $(div(a, b)), $(mod(a, b)), $(div(a, b) * b + mod(a, b) == a)");
julia> g(a, b) = println("div() and rem(): $a, $b, $(div(a, b)), $(rem(a, b)), $(div(a, b) * b + rem(a, b) == a)");
julia> f(a, b) = println("div() and %: $a, $b, $(div(a, b)), $(a % b), $(div(a, b) * b + a % b == a)");
julia> a = 21; b = 4; h(a, b); g(a, b); f(a, b);
div() and mod(): 21, 4, 5, 1, true
div() and rem(): 21, 4, 5, 1, true
div() and %: 21, 4, 5, 1, true
julia> a = 21; b = -4; h(a, b); g(a, b); f(a, b);
div() and mod(): 21, -4, -5, -3, false
div() and rem(): 21, -4, -5, 1, true
div() and %: 21, -4, -5, 1, true
julia> a = -21; b = 4; h(a, b); g(a, b); f(a, b);
div() and mod(): -21, 4, -5, 3, false
div() and rem(): -21, 4, -5, -1, true
div() and %: -21, 4, -5, -1, true
julia> a = -21; b = -4; h(a, b); g(a, b); f(a, b);
div() and mod(): -21, -4, 5, -1, true
div() and rem(): -21, -4, 5, -1, true
div() and %: -21, -4, 5, -1, true
結果は
除数,被除数の符号が同じときには,除数の計算に mod(),rem(), % のどれを使っても,等式は成り立つ。
除数,被除数の符号が違うときには,除数の計算に rem(), % のいずれを使っても,等式は成り立つが,mod() を使った場合は等式は成り立たない。
mod() は % とは違うということである。
ううん。こんなことばかりしているから,学習が進まない。
整数同士の割り算の,商と剰余についてまとめておく。
私が今まで使ったことのある言語についてのみであるが。
Prorog とか Pascal とか PL/I とかそのほかにもあるが,今となっては実行環境がないので,確かめることができない。
結果を先に述べておく。
2 つの整数を (a, b) とすると,それぞれの符号で 4 通りある。例として,(21, 4), (21, -4), (-21, 4), (-21, -4) でやってみる。
★★★ (商, 剰余) がそれぞれ (5, 1), (-5, 1), (-5, -1), (5, -1) となる言語
AWK, C, C#, C++, COBOL, D, F#, FORTRAN, Go, Java, JavaScript, PHP, Scala, Swift, VB
Haskel で quot() と rem() を使う場合,
Julia で div() と rem() を使う場合,
Perl でゼロ方向への丸めをするようにプログラムする場合
★★ (商, 剰余) がそれぞれ (5, 1), (-6, -3), (-6, 3), (5, -1) となる言語
Python2, Python3, R, Ruby,
Haskel で dif() と mod() を使う場合,
Julia で剰余の計算を a - div(a, b) * b で計算するようにプログラムする場合,
Perl で -∞ 方向への丸めを行い,剰余の計算を a - div(a, b) * b で計算するようにプログラムする場合
★ 迂闊にやると,(商, 剰余) がそれぞれ (5, 1), (-5, -3), (-5, 3), (5, -1) となる言語
Julia で div() と mod() を使う場合(誤った選択。div() と rem() を使えば ★★★,剰余の計算を自分ですれば ★★)
Perl で int($a / $b), と $a % $b を使う場合(適切にプログラムして ★★★ にするか ★★ にする)
このような場合,「 a = 商 * b + 剰余」が成り立たないので,不適切な解となってしまう。
========= AWK
BEGIN {
OFS = ", "
a = 21
b = 4
print int(a / b), a % b
}
========= C
#include
#include
int main(int argc, char **argv) {
int a = 21;
int b = 4;
printf("%d, %d\n", a / b, a % b);
return EXIT_SUCCESS;
}
========= C#
public class Hello{
public static void Main(){
int a, b;
a = 21;
b = 4;
System.Console.WriteLine(a / b + ", " + a % b);
}
}
========= C++
#include
int main(int argc, char **argv) {
int a = 21;
int b = 4;
std::cout <
return EXIT_SUCCESS;
}
========= COBOL
identification division.
program-id. Hello.
data division.
working-storage section.
01 working-area.
02 x pic s9.
02 y pic s9.
procedure division.
divide 21 by 4 giving x remainder y.
display x, ", ", y.
========= D
import std.stdio;
void main() {
int a, b;
a = 21;
b = 4;
writeln(a / b, ", ", a % b);
}
========= F#
let a = 21;;
let b = 4;;
printfn "%d, %d" (a / b) (a % b);;
========= Fortran
program main
implicit none
integer a, b
a = -21
b = -4
write(*, *) int(a / b), ", ", mod(a, b)
end program main
========= Go
package main
import "fmt"
func main() {
var a int = 21
var b int = 4
fmt.Printf("%d, %d", a / b, a % b)
}
========= Java
import java.util.*;
public class Main {
public static void main(String[] args) throws Exception {
int a = 21;
int b = 4;
System.out.println(a / b + ", " + a % b);
}
}
========= JavaScript
var a = 21;
var b = 4;
var x = a / b;
// 一律に Math.floor を紹介するページが多いが,a, b の符号が違うときには誤った答えになるので注意
x = x < 0 ? Math.ceil(x) : Math.floor(x)
console.log(x + ", " + a % b);
========= PHP
$a = 21;
$b = 4;
echo (int)($a / $b), ", ", $a % $b;
?>
========= Scala
object Main extends App {
var a = 21
var b = 4
println(a / b + ", " + a % b)
}
========= Swift
var a:Int = -23
var b:Int = 4
print("\(a / b), \(a % b)")
========= VB VisualBasic
public class compiler
shared function Main as integer
Dim a As Integer: a = -23
Dim b As Integer: b = 4
' int() は -∞方向への丸めなので不適切
Console.WriteLine(fix(a / b) & ", " & a Mod b)
return 0
end function
end class
###############################################
========= Julia
a = 21
b = 4
# ハイブリッド(不適切な実装)
println(div(a, b), ", ", mod(a,b))
# ゼロ方向へ丸め(C などと同じ多数派)
println(div(a, b), ", ", rem(a,b))
# -∞方向へ丸め(Python などと同じだが少数派)
x = div(a, b)
println(x, a - x * b)
========= Perl
$a = 21;
$b = 4;
# ハイブリッド(不適切な実装)
print int($a / $b), ', ', $a % $b;
# ゼロ方向へ丸め(C などと同じ多数派)
print int($a / $b), ', ', $a - int($a / $b) * $b;
# -∞方向へ丸め(Python などと同じだが少数派)
$x = $a / $b
$x = int($x) - $x < 0 ? 1 : 0
print $x, ', ', $a - $x * b;
###############################################
========= Haskell
main = do
let a = 21
let b = 4
-- ゼロ方向へ丸め(C などと同じ多数派)
putStrLn $ show(a `quot` b) ++ ", " ++ show(a `rem` b)
-- -∞方向へ丸め(Python などと同じだが少数派)
putStrLn $ show(a `div` b) ++ ", " ++ show(a `mod` b)
========= Python2
a = 21
b = 4
# -∞方向へ丸め(少数派)
print "%d, %d" % (a // b, a % b)
========= Python3
a = 21
b = 4
# -∞方向へ丸め(少数派)
print("%d, %d" % (a // b, a % b))
========= R
a = 21
b = 4
# -∞方向へ丸め(少数派)
cat(sprintf("%d, %d\n", a %/% b, a %% b))
========= Ruby
$a = 21
$b = 4
# -∞方向へ丸め(少数派)
print $a / $b, ', ', $a % $b
文字列中に,どのような文字が幾つあったか知りたいって...
>>> import numpy as np
>>> str = 'あいうえおあおaiueoao999112'
>>> index, count = np.unique(list(str), return_counts=True)
>>> index
array(['1', '2', '9', 'a', 'e', 'i', 'o', 'u', 'あ', 'い', 'う', 'え', 'お'],
dtype='<U1')
>>> count
array([2, 1, 3, 2, 1, 1, 2, 1, 2, 1, 1, 1, 2])
>>>
>>> list(index)
['1', '2', '9', 'a', 'e', 'i', 'o', 'u', 'あ', 'い', 'う', 'え', 'お']
>>> list(count)
[2, 1, 3, 2, 1, 1, 2, 1, 2, 1, 1, 1, 2]
組み合わせ
b の逆順列を作る invperm(v)
julia> v = [2; 4; 3; 1];
一番小さいものが何番目,二番目に小さいものが何番目,... というリストをつくる。
julia> invperm(v)
4-element Array{Int64,1}:
4
1
3
2
julia> A = ['a','b','c','d'];
julia> B = A[v]
4-element Array{Char,1}:
'b': ASCII/Unicode U+0062 (category Ll: Letter, lowercase)
'd': ASCII/Unicode U+0064 (category Ll: Letter, lowercase)
'c': ASCII/Unicode U+0063 (category Ll: Letter, lowercase)
'a': ASCII/Unicode U+0061 (category Ll: Letter, lowercase)
julia> B[invperm(v)]
4-element Array{Char,1}:
'a': ASCII/Unicode U+0061 (category Ll: Letter, lowercase)
'b': ASCII/Unicode U+0062 (category Ll: Letter, lowercase)
'c': ASCII/Unicode U+0063 (category Ll: Letter, lowercase)
'd': ASCII/Unicode U+0064 (category Ll: Letter, lowercase)
v が正しい順列ならば true を返す isperm(v)
julia> isperm([1; 2])
true
julia> isperm([1; 3])
false
インプレースで順列を作る permute!(v, p)
A を B の順番で取り出して並べる。
julia> A = [1, 1, 3, 4];
julia> perm = [2, 4, 3, 1];
julia> permute!(A, perm);
julia> A
4-element Array{Int64,1}:
1
4
3
1
インプレースで順列を作る invpermute!(v, p)
julia> A = [1, 1, 3, 4];
julia> perm = [2, 4, 3, 1];
julia> invpermute!(A, perm);
julia> A
4-element Array{Int64,1}:
4
1
3
1
逆順に並べたコピーを返す reverse(v [, start=1 [, stop=length(v) ]] )
julia> A = Vector(1:5)
5-element Array{Int64,1}:
1
2
3
4
5
julia> reverse(A)
5-element Array{Int64,1}:
5
4
3
2
1
julia> reverse(A, 1, 4)
5-element Array{Int64,1}:
4
3
2
1
5
julia> reverse(A, 3, 5)
5-element Array{Int64,1}:
1
2
5
4
3
インプレースで逆順 reverse!(v [, start=1 [, stop=length(v) ]]) -> v
julia> A = Vector(1:5)
5-element Array{Int64,1}:
1
2
3
4
5
julia> reverse!(A);
julia> A
5-element Array{Int64,1}:
5
4
3
2
1
dims で指定した次元について逆順にする reverse(A; dims::Integer)
julia> b = [1 2; 3 4]
2×2 Array{Int64,2}:
1 2
3 4
julia> reverse(b, dims=2)
2×2 Array{Int64,2}:
2 1
4 3
a, b, c, d の4個の数字を入力とする
もしどれかが 0 なら,それぞれに 0.5 を加える
x = a * d / (b * c)
としたとき,x か 1 / x の大きい方を返す関数を定義せよ
言語は問わない。合計文字数が少ない方がいいぞ!
解答例は,ずっとスクロールダウンして...
import numpy as np
def func(a, b, c, d):
if a * b * c * d == 0:
a, b, c, d = np.array([a, b, c, d])+0.5
OR = a * d / (b * c)
return max(OR, 1 / OR)
func(1,2,3,4) # 1.5
func(0,2,3,4) # 3.8888888888888893
配列関数
累積的な演算 accumulate(op, A; dims::Integer, [init])
累和
julia> accumulate(+, [1,2,3])
3-element Array{Int64,1}:
1
3
6
累積
julia> accumulate(*, [1,2,3])
3-element Array{Int64,1}:
1
2
6
julia> accumulate(+, [1,2,3]; init=100)
3-element Array{Int64,1}:
101
103
106
julia> accumulate(min, [1,2,-1]; init=0)
3-element Array{Int64,1}:
0
0
-1
julia> accumulate(+, fill(1, 3, 3), dims=1)
3×3 Array{Int64,2}:
1 1 1
2 2 2
3 3 3
julia> accumulate(+, fill(1, 3, 3), dims=2)
3×3 Array{Int64,2}:
1 2 3
1 2 3
1 2 3
累積的な演算。結果を B に保存 accumulate!(op, B, A; [dims], [init])
julia> x = [1, 0, 2, 0, 3];
julia> y = [0, 0, 0, 0, 0];
julia> accumulate!(+, y, x);
julia> y
5-element Array{Int64,1}:
1
1
3
3
6
julia> A = [1 2; 3 4];
julia> B = [0 0; 0 0];
julia> accumulate!(-, B, A, dims=1);
julia> B
2×2 Array{Int64,2}:
1 2
-2 -2
julia> accumulate!(-, B, A, dims=2);
julia> B
2×2 Array{Int64,2}:
1 -1
3 -1
指定された次元について累積 cumprod(A; dims::Integer)
julia> a = [1 2 3; 4 5 6]
2×3 Array{Int64,2}:
1 2 3
4 5 6
julia> cumprod(a, dims=1)
2×3 Array{Int64,2}:
1 2 3
4 10 18
julia> cumprod(a, dims=2)
2×3 Array{Int64,2}:
1 2 6
4 20 120
イテレーターの累積 cumprod(itr)
julia> cumprod(fill(1//2, 3))
3-element Array{Rational{Int64},1}:
1//2
1//4
1//8
julia> cumprod([fill(1//3, 2, 2) for i in 1:3])
3-element Array{Array{Rational{Int64},2},1}:
[1//3 1//3; 1//3 1//3]
[2//9 2//9; 2//9 2//9]
[4//27 4//27; 4//27 4//27]
julia> cumprod((1, 2, 1))
(1, 2, 2)
julia> cumprod(x^2 for x in 1:3)
3-element Array{Int64,1}:
1
4
36
累積結果を B に保存する cumprod!(B, A; dims::Integer)
累和 cumsum(A; dims::Integer)
julia> a = [1 2 3; 4 5 6]
2×3 Array{Int64,2}:
1 2 3
4 5 6
julia> cumsum(a, dims=1)
2×3 Array{Int64,2}:
1 2 3
5 7 9
julia> cumsum(a, dims=2)
2×3 Array{Int64,2}:
1 3 6
4 9 15
イテレータの累和 cumsum(itr)
julia> cumsum([1, 1, 1])
3-element Array{Int64,1}:
1
2
3
julia> cumsum([fill(1, 2) for i in 1:3])
3-element Array{Array{Int64,1},1}:
[1, 1]
[2, 2]
[3, 3]
julia> cumsum((1, 1, 1))
(1, 2, 3)
julia> cumsum(x^2 for x in 1:3)
3-element Array{Int64,1}:
1
5
14
累和の結果を B に保存 cumsum!(B, A; dims::Integer)
差分 diff(A::AbstractVector),diff(A::AbstractArray; dims::Integer)
julia> a = [2 4; 6 16]
2×2 Array{Int64,2}:
2 4
6 16
julia> diff(a, dims=2)
2×1 Array{Int64,2}:
2
10
julia> diff(vec(a))
3-element Array{Int64,1}:
4
-2
12
配列を繰り返して配列を作る repeat(A::AbstractArray, counts::Integer...)
julia> repeat([1, 2, 3], 2)
6-element Array{Int64,1}:
1
2
3
1
2
3
julia> repeat([1, 2, 3], 2, 3)
6×3 Array{Int64,2}:
1 1 1
2 2 2
3 3 3
1 1 1
2 2 2
3 3 3
文字列を繰り返して文字列を作る repeat(s::AbstractString, r::Integer)
julia> repeat("ha", 3)
"hahaha"
julia> repeat('A', 3)
"AAA"
行列を 180度回転する rot180(A)
julia> a = [1 2; 3 4]
2×2 Array{Int64,2}:
1 2
3 4
julia> rot180(a)
2×2 Array{Int64,2}:
4 3
2 1
行列を k 回,180度回転する rot180(A, k)
k が偶数なら,copy と同じである。
julia> a = [1 2; 3 4]
2×2 Array{Int64,2}:
1 2
3 4
julia> rot180(a,1)
2×2 Array{Int64,2}:
4 3
2 1
julia> rot180(a,2)
2×2 Array{Int64,2}:
1 2
3 4
行列を左に 90 度回転する rotl90(A)
julia> a = [1 2; 3 4]
2×2 Array{Int64,2}:
1 2
3 4
julia> rotl90(a)
2×2 Array{Int64,2}:
2 4
1 3
行列を左に 90 度,k 回回転する rotl90(A, k)
k が 4 の倍数ならば,コピーと同じである。
julia> a = [1 2; 3 4]
2×2 Array{Int64,2}:
1 2
3 4
julia> rotl90(a,1)
2×2 Array{Int64,2}:
2 4
1 3
julia> rotl90(a,2)
2×2 Array{Int64,2}:
4 3
2 1
julia> rotl90(a,3)
2×2 Array{Int64,2}:
3 1
4 2
julia> rotl90(a,4)
2×2 Array{Int64,2}:
1 2
3 4
行列を右に 90 度回転する rotr90(A)
julia> a = [1 2; 3 4]
2×2 Array{Int64,2}:
1 2
3 4
julia> rotr90(a)
2×2 Array{Int64,2}:
3 1
4 2
行列を右に 90 度回転する rotr90(A,k)
julia> a = [1 2; 3 4]
2×2 Array{Int64,2}:
1 2
3 4
julia> rotr90(a,1)
2×2 Array{Int64,2}:
3 1
4 2
julia> rotr90(a,2)
2×2 Array{Int64,2}:
4 3
2 1
julia> rotr90(a,3)
2×2 Array{Int64,2}:
2 4
1 3
julia> rotr90(a,4)
2×2 Array{Int64,2}:
1 2
3 4
配列の指定された次元について関数で変換する mapslices(f, A; dims)
julia> a = reshape(Vector(1:16),(2,2,2,2))
2×2×2×2 Array{Int64,4}:
[:, :, 1, 1] =
1 3
2 4
[:, :, 2, 1] =
5 7
6 8
[:, :, 1, 2] =
9 11
10 12
[:, :, 2, 2] =
13 15
14 16
julia> mapslices(sum, a, dims = [1,2])
1×1×2×2 Array{Int64,4}:
[:, :, 1, 1] =
10
[:, :, 2, 1] =
26
[:, :, 1, 2] =
42
[:, :, 2, 2] =
58
行列の最初の次元をイテレートするジェネレータを作る eachrow(A::AbstractVecOrMat)
julia> a = [1 2; 3 4]
2×2 Array{Int64,2}:
1 2
3 4
julia> first(eachrow(a))
2-element view(::Array{Int64,2}, 1, :) with eltype Int64:
1
2
julia> collect(eachrow(a))
2-element Array{SubArray{Int64,1,Array{Int64,2},Tuple{Int64,Base.Slice{Base.OneTo{Int64}}},true},1}:
[1, 2]
[3, 4]
行列の2番目の次元をイテレートするジェネレータを作る eachcol(A::AbstractVecOrMat)
julia> a = [1 2; 3 4]
2×2 Array{Int64,2}:
1 2
3 4
julia> first(eachcol(a))
2-element view(::Array{Int64,2}, :, 1) with eltype Int64:
1
3
julia> collect(eachcol(a))
2-element Array{SubArray{Int64,1,Array{Int64,2},Tuple{Base.Slice{Base.OneTo{Int64}},Int64},true},1}:
[1, 3]
[2, 4]
両方の次元をイテレートするジェネレータを作る eachslice(A::AbstractArray; dims)
配列の連接 cat(), vcat(), hcat()
vcat() は第 1 次元で cat()
julia> a = [1 2 3 4 5]
1×5 Array{Int64,2}:
1 2 3 4 5
julia> b = [6 7 8 9 10; 11 12 13 14 15]
2×5 Array{Int64,2}:
6 7 8 9 10
11 12 13 14 15
julia> vcat(a,b)
3×5 Array{Int64,2}:
1 2 3 4 5
6 7 8 9 10
11 12 13 14 15
julia> c = ([1 2 3], [4 5 6])
([1 2 3], [4 5 6])
julia> vcat(c...)
2×3 Array{Int64,2}:
1 2 3
4 5 6
hcat() は第 2 次元で cat()
julia> a = [1; 2; 3; 4; 5]
5-element Array{Int64,1}:
1
2
3
4
5
julia> b = [6 7; 8 9; 10 11; 12 13; 14 15]
5×2 Array{Int64,2}:
6 7
8 9
10 11
12 13
14 15
julia> hcat(a,b)
5×3 Array{Int64,2}:
1 6 7
2 8 9
3 10 11
4 12 13
5 14 15
julia> c = ([1; 2; 3], [4; 5; 6])
([1, 2, 3], [4, 5, 6])
julia> hcat(c...)
3×2 Array{Int64,2}:
1 4
2 5
3 6
julia> x = Matrix(undef, 3, 0) # x = [] would have created an Array{Any, 1}, but need an Array{Any, 2}
3×0 Array{Any,2}
julia> hcat(x, [1; 2; 3])
3×1 Array{Any,2}:
1
2
3
hvcat() は hcat() と vcat() を 1 回のコールで行う。
julia> a, b, c, d, e, f = 1, 2, 3, 4, 5, 6
(1, 2, 3, 4, 5, 6)
julia> [a b c; d e f]
2×3 Array{Int64,2}:
1 2 3
4 5 6
julia> hvcat((3,3), a,b,c,d,e,f)
2×3 Array{Int64,2}:
1 2 3
4 5 6
julia> [a b;c d; e f]
3×2 Array{Int64,2}:
1 2
3 4
5 6
julia> hvcat((2,2,2), a,b,c,d,e,f)
3×2 Array{Int64,2}:
1 2
3 4
5 6
ベクトルを作る vect(X...)
julia> a = Base.vect(UInt8(1), 2.5, 1//2)
3-element Array{Float64,1}:
1.0
2.5
0.5
ローテート circshift(A, shift),circshift!(dest, src, shifts)
shift はタプルまたはベクトル。それぞれの次元でどれだけシフトするかの量を表す。正・負・ゼロの値を取る。
circshift! は結果を dest に格納する。
julia> b = reshape(Vector(1:16), (4,4))
4×4 Array{Int64,2}:
1 5 9 13
2 6 10 14
3 7 11 15
4 8 12 16
julia> circshift(b, (0,2))
4×4 Array{Int64,2}:
9 13 1 5
10 14 2 6
11 15 3 7
12 16 4 8
julia> circshift(b, (-1,0))
4×4 Array{Int64,2}:
2 6 10 14
3 7 11 15
4 8 12 16
1 5 9 13
julia> a = BitArray([true, true, false, false, true])
5-element BitArray{1}:
1
1
0
0
1
julia> circshift(a, 1)
5-element BitArray{1}:
1
1
1
0
0
julia> circshift(a, -1)
5-element BitArray{1}:
1
0
0
1
1
julia> src = reshape(Vector(1:16), (4,4))
4×4 Array{Int64,2}:
1 5 9 13
2 6 10 14
3 7 11 15
4 8 12 16
julia> dest = OffsetArray{Int}(undef, (0:3,2:5))
julia> circcopy!(dest, src)
OffsetArrays.OffsetArray{Int64,2,Array{Int64,2}} with indices 0:3×2:5:
8 12 16 4
5 9 13 1
6 10 14 2
7 11 15 3
julia> dest[1:3,2:4] == src[1:3,2:4]
true
配列の要素が true のもののインデックスを取り出す findall(), findall(f::Function, A)
julia> A = [true, false, false, true]
4-element Array{Bool,1}:
1
0
0
1
julia> findall(A)
2-element Array{Int64,1}:
1
4
julia> A = [true false; false true]
2×2 Array{Bool,2}:
1 0
0 1
julia> findall(A)
2-element Array{CartesianIndex{2},1}:
CartesianIndex(1, 1)
CartesianIndex(2, 2)
julia> findall(falses(3))
Int64[]
julia> x = [1, 3, 4]
3-element Array{Int64,1}:
1
3
4
julia> findall(isodd, x)
2-element Array{Int64,1}:
1
2
julia> A = [1 2 0; 3 4 0]
2×3 Array{Int64,2}:
1 2 0
3 4 0
julia> findall(isodd, A)
2-element Array{CartesianIndex{2},1}:
CartesianIndex(1, 1)
CartesianIndex(2, 1)
julia> findall(!iszero, A)
4-element Array{CartesianIndex{2},1}:
CartesianIndex(1, 1)
CartesianIndex(2, 1)
CartesianIndex(1, 2)
CartesianIndex(2, 2)
julia> d = Dict(:A => 10, :B => -1, :C => 0)
Dict{Symbol,Int64} with 3 entries:
:A => 10
:B => -1
:C => 0
julia> findall(x -> x >= 0, d)
2-element Array{Symbol,1}:
:A
:C
最初に見つかる true のインデックスを返す findfirst(A), findfirst(predicate::Funciton, A)
julia> A = [false, false, true, false]
4-element Array{Bool,1}:
0
0
1
0
julia> findfirst(A)
3
julia> findfirst(falses(3)) # returns nothing, but not printed in the REPL
julia> A = [false false; true false]
2×2 Array{Bool,2}:
0 0
1 0
julia> findfirst(A)
CartesianIndex(2, 1)
julia> A = [1, 4, 2, 2]
4-element Array{Int64,1}:
1
4
2
2
julia> findfirst(iseven, A)
2
julia> findfirst(x -> x>10, A) # returns nothing, but not printed in the REPL
julia> findfirst(isequal(4), A)
2
julia> A = [1 4; 2 2]
2×2 Array{Int64,2}:
1 4
2 2
julia> findfirst(iseven, A)
CartesianIndex(2, 1)
最後に見つかる true のインデックスを返す findlast(A), findlast(predicate::Function, A)
julia> A = [true, false, true, false]
4-element Array{Bool,1}:
1
0
1
0
julia> findlast(A)
3
julia> A = falses(2,2);
julia> findlast(A) # returns nothing, but not printed in the REPL
julia> A = [true false; true false]
2×2 Array{Bool,2}:
1 0
1 0
julia> findlast(A)
CartesianIndex(2, 1)
julia> A = [1, 2, 3, 4]
4-element Array{Int64,1}:
1
2
3
4
julia> findlast(isodd, A)
3
julia> findlast(x -> x > 5, A) # returns nothing, but not printed in the REPL
julia> A = [1 2; 3 4]
2×2 Array{Int64,2}:
1 2
3 4
julia> findlast(isodd, A)
CartesianIndex(2, 1)
i 以後の次の true インデックスを返す findnext(A, i),findnext(predicate::Function, A, i)
julia> A = [false, false, true, false]
4-element Array{Bool,1}:
0
0
1
0
julia> findnext(A, 1)
3
julia> findnext(A, 4) # returns nothing, but not printed in the REPL
julia> A = [false false; true false]
2×2 Array{Bool,2}:
0 0
1 0
julia> findnext(A, CartesianIndex(1, 1))
CartesianIndex(2, 1)
julia> A = [1, 4, 2, 2];
julia> findnext(isodd, A, 1)
1
julia> findnext(isodd, A, 2) # returns nothing, but not printed in the REPL
julia> A = [1 4; 2 2];
julia> findnext(isodd, A, CartesianIndex(1, 1))
CartesianIndex(1, 1)
i 以前の true インデックスを返す findprev(A, i),findprev(predicate::Function A, i)
julia> A = [false, false, true, true]
4-element Array{Bool,1}:
0
0
1
1
julia> findprev(A, 3)
3
julia> findprev(A, 1) # returns nothing, but not printed in the REPL
julia> A = [false false; true true]
2×2 Array{Bool,2}:
0 0
1 1
julia> findprev(A, CartesianIndex(2, 1))
CartesianIndex(2, 1)
julia> A = [4, 6, 1, 2]
4-element Array{Int64,1}:
4
6
1
2
julia> findprev(isodd, A, 1) # returns nothing, but not printed in the REPL
julia> findprev(isodd, A, 3)
3
julia> A = [4 6; 1 2]
2×2 Array{Int64,2}:
4 6
1 2
julia> findprev(isodd, A, CartesianIndex(1, 2))
CartesianIndex(2, 1)
対角要素を中心に右上と左下を入れ替える permutedims(m)
転置 transpose とは異なる。
julia> a = [1 2; 3 4];
julia> b = [5 6; 7 8];
julia> c = [9 10; 11 12];
julia> d = [13 14; 15 16];
julia> X = [[a] [b]; [c] [d]]
2×2 Array{Array{Int64,2},2}:
[1 2; 3 4] [5 6; 7 8]
[9 10; 11 12] [13 14; 15 16]
julia> permutedims(X)
2×2 Array{Array{Int64,2},2}:
[1 2; 3 4] [9 10; 11 12]
[5 6; 7 8] [13 14; 15 16]
julia> transpose(X)
2×2 Transpose{Transpose{Int64,Array{Int64,2}},Array{Array{Int64,2},2}}:
[1 3; 2 4] [9 11; 10 12]
[5 7; 6 8] [13 15; 14 16]
julia> permutedims([1, 2, 3, 4])
1×4 Array{Int64,2}:
1 2 3 4
julia> V = [[[1 2; 3 4]]; [[5 6; 7 8]]]
2-element Array{Array{Int64,2},1}:
[1 2; 3 4]
[5 6; 7 8]
julia> permutedims(V)
1×2 Array{Array{Int64,2},2}:
[1 2; 3 4] [5 6; 7 8]
julia> transpose(V)
1×2 Transpose{Transpose{Int64,Array{Int64,2}},Array{Array{Int64,2},1}}:
[1 3; 2 4] [5 7; 6 8]
コピーを伴わない permutedims PermuteDimsArray(A, perm) -> B
julia> A = rand(3,5,4);
julia> B = PermutedDimsArray(A, (3,1,2));
julia> size(B)
(4, 3, 5)
julia> B[3,1,2] == A[1,2,3]
true
次元属性が一致するかどうか promote_shape(s1, s2)
julia> a = fill(1, (3,4,1,1,1));
julia> b = fill(1, (3,4));
julia> promote_shape(a,b)
(Base.OneTo(3), Base.OneTo(4), Base.OneTo(1), Base.OneTo(1), Base.OneTo(1))
julia> promote_shape((2,3,1,4), (2, 3, 1, 4, 1))
(2, 3, 1, 4, 1)
参照(indexing)と代入(assignment)
getindex(), setindex()
列優先である。
julia> A = [1 2; 3 4]
2×2 Array{Int64,2}:
1 2
3 4
julia> getindex(A, 1)
1
julia> getindex(A, [2, 1])
2-element Array{Int64,1}:
3
1
julia> getindex(A, 2:4)
3-element Array{Int64,1}:
3
2
4
setindex!(A, X, inds...) と A[inds...] は同じである。
julia> A = zeros(2,2);
julia> setindex!(A, [10, 20], [1, 2]); # A のインデックス 1,2 に 10, 20 を代入
julia> A[[3, 4]] = [30, 40]; # A のインデックス 3,4 に 30, 40 を代入
julia> A
2×2 Array{Float64,2}:
10.0 30.0
20.0 40.0
配列がインデックスを持つか isassigned()
julia> isassigned(rand(3, 3), 5) # 配列は 1 ~ 9 のインデックスを持ちうる
true
julia> isassigned(rand(3, 3), 3 * 3 + 1) # 従って 3 * 3 + 1 = 10 というインデックスは持たない
false
julia> mutable struct Foo end
julia> v = similar(rand(3), Foo)
3-element Array{Foo,1}:
#undef
#undef
#undef
julia> isassigned(v, 1)
false
コロン ':'
julia> A = reshape(Vector(1:16), (2, 2, 2, 2))
2×2×2×2 Array{Int64,4}:
[:, :, 1, 1] =
1 3
2 4
[:, :, 2, 1] =
5 7
6 8
[:, :, 1, 2] =
9 11
10 12
[:, :, 2, 2] =
13 15
14 16
julia> A[CartesianIndex((1, 1, 1, 1))]
1
julia> A[CartesianIndex((1, 1, 1, 2))]
9
julia> A[CartesianIndex((1, 1, 2, 1))]
5
LinearIndices()
julia> A = reshape(Vector(1:16), (2, 2, 2, 2))
2×2×2×2 Array{Int64,4}:
[:, :, 1, 1] =
1 3
2 4
[:, :, 2, 1] =
5 7
6 8
[:, :, 1, 2] =
9 11
10 12
[:, :, 2, 2] =
13 15
14 16
julia> A[CartesianIndex((1, 1, 1, 1))]
1
julia> A[CartesianIndex((1, 1, 1, 2))]
9
julia> A[CartesianIndex((1, 1, 2, 1))]
5
julia> A = fill(1, (5,6,7));
julia> b = LinearIndices(A);
julia> extrema(b)
(1, 210)
1からはじまる整数列を要素に持つ配列 LinearIndices()
julia> linear = LinearIndices((1:3, 1:2))
3×2 LinearIndices{2,Tuple{UnitRange{Int64},UnitRange{Int64}}}:
1 4
2 5
3 6
julia> linear[1,2]
4
julia> LinearIndices((1:2,1:3, 2:5))
2×3×4 LinearIndices{3,Tuple{UnitRange{Int64},UnitRange{Int64},UnitRange{Int64}}}:
[:, :, 1] =
1 3 5
2 4 6
[:, :, 2] =
7 9 11
8 10 12
[:, :, 3] =
13 15 17
14 16 18
[:, :, 4] =
19 21 23
20 22 24
インデックス I が A の範囲内にあるか checkbounds(Bool, A, I...)
julia> A = rand(3, 3);
julia> checkbounds(Bool, A, 2)
true
julia> checkbounds(Bool, A, 3, 4)
false
julia> checkbounds(Bool, A, 1:3)
true
julia> checkbounds(Bool, A, 1:3, 2:4)
false
インデックス I が A の範囲内になければエラーにする checkbounds(A, I...)
julia> checkindex(Bool, 1:20, 8)
true
julia> checkindex(Bool, 1:20, 21)
false
配列を参照する view(A, inds...)
julia> A = [1 2; 3 4]
2×2 Array{Int64,2}:
1 2
3 4
julia> b = view(A, :, 1)
2-element view(::Array{Int64,2}, :, 1) with eltype Int64:
1
3
julia> fill!(b, 0)
2-element view(::Array{Int64,2}, :, 1) with eltype Int64:
0
0
julia> A # Note A has changed even though we modified b
2×2 Array{Int64,2}:
0 2
0 4
配列の次元サイズの変更 reshape()
julia> A = Vector(1:16)
16-element Array{Int64,1}:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
julia> reshape(A, (4, 4))
4×4 Array{Int64,2}:
1 5 9 13
2 6 10 14
3 7 11 15
4 8 12 16
julia> reshape(A, 2, :)
2×8 Array{Int64,2}:
1 3 5 7 9 11 13 15
2 4 6 8 10 12 14 16
julia> reshape(1:6, 2, 3)
2×3 reshape(::UnitRange{Int64}, 2, 3) with eltype Int64:
1 3 5
2 4 6
配列の次元を削除する drop(A; dims)
julia> a = reshape(Vector(1:4),(2,2,1,1))
2×2×1×1 Array{Int64,4}:
[:, :, 1, 1] =
1 3
2 4
julia> dropdims(a; dims=3)
2×2×1 Array{Int64,3}:
[:, :, 1] =
1 3
2 4
配列をベクトルにする vec()
julia> a = [1 2 3; 4 5 6]
2×3 Array{Int64,2}:
1 2 3
4 5 6
julia> vec(a)
6-element Array{Int64,1}:
1
4
2
5
3
6
julia> vec(1:3)
1:3
ベクトルの作成と初期化
Vector{T}(undef, n)
初期化されていない,要素数 n の 型 T のベクトルを作る
julia> Vector{Float64}(undef, 3)
3-element Array{Float64,1}:
2.2910037355e-314
2.2881675853e-314
2.2881675853e-314
julia> Vector{Union{Nothing, String}}(nothing, 2)
2-element Array{Union{Nothing, String},1}:
nothing
nothing
julia> Vector{Union{Missing, String}}(missing, 2)
2-element Array{Union{Missing, String},1}:
missing
missing
二次元行列の作成
型 T の二次元配列 Matrix{T} <: AbstractMatrix{T}
julia> Matrix{Float64}(undef, 2, 3)
2×3 Array{Float64,2}:
0.0 2.36894e-314 1.0e-323
5.0e-324 6.0e-323 2.36894e-314
julia> Matrix{Union{Nothing, String}}(nothing, 2, 3)
2×3 Array{Union{Nothing, String},2}:
nothing nothing nothing
nothing nothing nothing
julia> Matrix{Union{Missing, String}}(missing, 2, 3)
2×3 Array{Union{Missing, String},2}:
missing missing missing
missing missing missing
[] によるベクトル
julia> Int8[1, 2, 3]
3-element Array{Int8,1}:
1
2
3
getindex() によるベクトル
julia> A = [1 2; 3 4]
2×2 Array{Int64,2}:
1 2
3 4
julia> getindex(A, 1)
1
julia> getindex(A, [2, 1])
2-element Array{Int64,1}:
3
1
julia> getindex(A, 2:4)
3-element Array{Int64,1}:
3
2
4
zeros() による配列
zeros([T=Float64,] dims::Tuple)
zeros([T=Float64,] dims...)
julia> zeros(5)
5-element Array{Float64,1}:
0.0
0.0
0.0
0.0
0.0
julia> zeros(Int8, 2, 3)
2×3 Array{Int8,2}:
0 0 0
0 0 0
ones() による配列
ones([T=Float64,] dims::Tuple)
ones([T=Float64,] dims...)
julia> ones(1,5)
1×5 Array{Float64,2}:
1.0 1.0 1.0 1.0 1.0
julia> ones(ComplexF64, 2, 3)
2×3 Array{Complex{Float64},2}:
1.0+0.0im 1.0+0.0im 1.0+0.0im
1.0+0.0im 1.0+0.0im 1.0+0.0im
BitArray
BitArray(undef, dims::Integer...)
BitArray{N}(undef, dims::NTuple{N,Int})
julia> BitArray(undef, 2, 2)
2×2 BitArray{2}:
0 0
0 0
julia> BitArray(undef, (3, 1))
3×1 BitArray{2}:
0
0
0
イテラブル・オブジェクトで BitArray を作る BitArray(itr)
julia> BitArray([1 0; 0 1])
2×2 BitArray{2}:
1 0
0 1
julia> BitArray(x+y == 3 for x = 1:2, y = 1:3)
2×3 BitArray{2}:
0 1 0
1 0 0
julia> BitArray(x+y == 3 for x = 1:2 for y = 1:3)
6-element BitArray{1}:
0
1
0
1
0
0
trues() で BitArray を作る trues(dims)
julia> trues(2,3)
2×3 BitArray{2}:
1 1 1
1 1 1
falses() で BitArray を作る falses(dims)
julia> falses(2,3)
2×3 BitArray{2}:
0 0 0
0 0 0
fill() で 配列を作る fill(x, dims::Tuple),fill(x, dims...)
全ての要素が x である,次元 dim の配列を作る
julia> fill(1.0, (2,3))
2×3 Array{Float64,2}:
1.0 1.0 1.0
1.0 1.0 1.0
julia> fill(42)
0-dimensional Array{Int64,0}:
42
x がオブジェクトの参照ならば,全ての要素は同じオブジェクトを参照する。
julia> A = fill(zeros(2), 2);
julia> A[1][1] = 42; # modifies both A[1][1] and A[2][1]
julia> A
2-element Array{Array{Float64,1},1}:
[42.0, 0.0]
[42.0, 0.0]
fill!() で配列を作る
fill!(A, Foo()) は, Foo() を 1 回だけ評価した値で満たされた A を返す。
julia> A = zeros(2,3)
2×3 Array{Float64,2}:
0.0 0.0 0.0
0.0 0.0 0.0
julia> fill!(A, 2.)
2×3 Array{Float64,2}:
2.0 2.0 2.0
2.0 2.0 2.0
julia> a = [1, 1, 1]; A = fill!(Vector{Vector{Int}}(undef, 3), a); a[1] = 2; A
3-element Array{Array{Int64,1},1}:
[2, 1, 1]
[2, 1, 1]
[2, 1, 1]
julia> x = 0; f() = (global x += 1; x); fill!(Vector{Int}(undef, 3), f())
3-element Array{Int64,1}:
1
1
1
similar() で配列を作る
similar(array, [element_type=eltype(array)], [dims=size(array)])
julia> similar(1:10, 1, 4)
1×4 Array{Int64,2}:
4419743872 4374413872 4419743888 0
julia> similar(trues(10,10), 2)
2-element BitArray{1}:
0
0
julia> similar(falses(10), Float64, 2, 4)
2×4 Array{Float64,2}:
2.18425e-314 2.18425e-314 2.18425e-314 2.18425e-314
2.18425e-314 2.18425e-314 2.18425e-314 2.18425e-314
ブロードキャストとベクトル化 broadcast()
julia> A = [1, 2, 3, 4, 5]
5-element Array{Int64,1}:
1
2
3
4
5
julia> B = [1 2; 3 4; 5 6; 7 8; 9 10]
5×2 Array{Int64,2}:
1 2
3 4
5 6
7 8
9 10
julia> broadcast(+, A, B)
5×2 Array{Int64,2}:
2 3
5 6
8 9
11 12
14 15
julia> parse.(Int, ["1", "2"])
2-element Array{Int64,1}:
1
2
julia> abs.((1, -2))
(1, 2)
julia> broadcast(+, 1.0, (0, -2.0))
(1.0, -1.0)
julia> (+).([[0,2], [1,3]], Ref{Vector{Int}}([1,-1]))
2-element Array{Array{Int64,1},1}:
[1, 1]
[2, 2]
julia> string.(("one","two","three","four"), ": ", 1:4)
4-element Array{String,1}:
"one: 1"
"two: 2"
"three: 3"
"four: 4"
broadcast!()
julia> A = [1.0; 0.0]; B = [0.0; 0.0];
julia> broadcast!(+, B, A, (0, -2.0));
julia> B
2-element Array{Float64,1}:
1.0
-2.0
julia> A
2-element Array{Float64,1}:
1.0
0.0
julia> broadcast!(+, A, A, (0, -2.0));
julia> A
2-element Array{Float64,1}:
1.0
-2.0
ベクトル化演算 @. expr
julia> x = 1.0:3.0; y = similar(x);
julia> @. y = x + 3 * sin(x)
3-element Array{Float64,1}:
3.5244129544236893
4.727892280477045
3.4233600241796016
基本的な関数
要素の型 eltype(A)
julia> A = [1 2 3;4 5 6]
2×3 Array{Int64,2}:
1 2 3
4 5 6
julia> eltype(A)
Int64
julia> B = [1.0 2.0; 3.0 4.0]
2×2 Array{Float64,2}:
1.0 2.0
3.0 4.0
julia> eltype(B)
Float64
総要素数 length(A)
julia> length(A)
6
julia> length(B)
4
次元数 ndims(A)
julia> ndims(A)
2
julia> B = [1 2 3 4 5 6 7 8 9 10] # 1行10列の配列
1×10 Array{Int64,2}:
1 2 3 4 5 6 7 8 9 10
julia> ndims(B)
2
julia> C = 1:10
1:10
julia> ndims(C) # 1次元の配列(ベクトル)
1
各次元の大きさ size(A)
julia> size(A)
(2, 3)
julia> size(C)
(10,)
指定した次元の大きさ size(A, n)
julia> size(A, 1)
2
julia> size(A, 2)
3
julia> size(C, 1)
10
有効な添え字範囲 axes(A)
julia> axes(A)
(Base.OneTo(2), Base.OneTo(3))
julia> axes(C)
(Base.OneTo(10),)
指定した次元の有効な添え字範囲 axes(A, n)
julia> axes(A, 1)
Base.OneTo(2)
julia> axes(A, 2)
Base.OneTo(3)
julia> axes(C, 1)
Base.OneTo(10)
全要素を網羅する効率のよいイテレータ eachindex(A)
julia> eachindex(A)
Base.OneTo(6)
julia> eachindex(B)
Base.OneTo(4)
julia> eachindex(C)
Base.OneTo(10)
julia> A = [1 2; 3 4];
julia> for i in eachindex(A) # linear indexing
println(i)
end
1
2
3
4
julia> for i in eachindex(view(A, 1:2, 1:1)) # Cartesian indexing
println(i)
end
CartesianIndex(1, 1)
CartesianIndex(2, 1)
各次元ごとの隣接する要素のメモリ上の距離 strides(A)
julia> D = [1 2 3;4 5 6;7 8 9;10 11 12]
4×3 Array{Int64,2}:
1 2 3
4 5 6
7 8 9
10 11 12
julia> stride(D)
(1, 4)
指定した次元での隣接する要素のメモリ上の距離 stride(A, n)
julia> stride(D, 1)
1
julia> stride(D, 2)
4
配列の作成と初期化
Array{T}(undef dims)
Array{T, N}(undef dims)
初期化しない(undef),型 T の,N 次元配列(それぞれの次元サイズは dim)を作る。
dim は タプルか,複数の整数。N が明示されないときは dim の長さを使う。
型は,Float64, Int64, Union{Nothing, String} などのように指定する。
Float64 の,2次元配列を作る。初期化しない(undef)。それぞれの次元サイズは 3, 4。
julia> A = Array{Float64,2}(undef, 3, 4)
3×4 Array{Float64,2}:
2.38811e-314 2.38811e-314 2.38811e-314 2.38838e-314
2.38811e-314 2.38811e-314 2.38838e-314 2.38841e-314
2.38811e-314 2.38811e-314 2.38838e-314 2.54817e-314
Int64 の,二次元配列を作る。初期化しない。それぞれの次元サイズは 2, 3。
julia> B = Array{Int64}(undef, 2, 3)
2×3 Array{Int64,2}:
4529053184 74 0
4529478432 30 4632025920
Union{Missing, String} 型の配列。初期化は missing(missing value)。
julia> Array{Union{Missing, String}}(missing, 2)
2-element Array{Union{Missing, String},1}:
missing
missing
julia> Array{Union{Missing, Int}}(missing, 2, 3)
2×3 Array{Union{Missing, Int64},2}:
missing missing missing
missing missing missing
UndefInitializer() は undef と同じもの。
julia> Array{Float64,1}(UndefInitializer(), 3)
3-element Array{Float64,1}:
2.2883369826e-314
2.368470051e-314
2.3656390153e-314
制御構文
複合式 begin, ;
begin と end で囲まれた式を,順に実行する。最後の式の評価値が返される。
julia> z = begin
x = 1
y = 2
x + y
end
3
1 行に 1 つの式しか書けないということではない。一行にまとめて書くこともできる。それぞれの式は ';' で区切ればよい。
julia> begin x = 1; y = 2; x + y end
3
'begin' と 'end' で囲む代わりに '( )' で囲んでもよい。
julia> z = (x = 1; y = 2; x + y)
3
もちろん,この場合も行を分けてもよい。
julia> (x = 1;
y = 2;
x + y)
3
条件評価 if-elseif-else, 三項演算子 ?:
julia> function test(x, y)
if x < y
println("x is less than y")
elseif x > y
println("x is greater than y")
else
println("x is equal to y")
end
end
test (generic function with 2 methods)
julia> test(1, 2)
x is less than y
julia> test(2, 1)
x is greater than y
julia> test(1, 1)
x is equal to y
他のプログラム言語とは違うかもしれないが,Julia の if ブロックはローカルスコープを作らないので,if ブロック内で定義された変数はその外でも使える(筆者注:多くの言語経験者は,「当たり前だろう」と思うかも知れないが)。
Julia の if ブロックは,最後に実行された文(式)の値を戻り値とする。
julia> x = 3;
julia> if x > 0
"positive!"
else
"negative..."
end
"positive!"
他の多くのプログラミング言語とは異なり,条件式は true か false いずれかの評価値を持つものでなければならない。
julia> if 1 println("true") end
ERROR: TypeError: non-boolean (Int64) used in boolean context
julia> if true println("true") end
true
2 つ上の例は,三項演算子を用いて書くことができる。
julia> x = 10; x > 0 ? "positive!" : "negative..."
"positive!"
julia> x = -10; x > 0 ? "positive!" : "negative..."
"negative..."
複雑にすることも出来る。
julia> test(x, y) = println(x < y ? "x is less than y" :
x > y ? "x is greater than y" : "x is equal to y")
test (generic function with 2 methods)
julia> test(1, 2)
x is less than y
julia> test(2, 1)
x is greater than y
julia> test(1, 1)
x is equal to y
ショート・サーキット評価 &&, ||, チェイン比較
a && b という論理式で,a が true のときのみ b が評価される。
a || b という論理式で,a が false のときのみ b が評価される。
if end は, && と同じである。
if ! end は, || と同じである。
これにより,if ブロックを書かずに式を記述できる。
julia> function fact(n::Int)
n >= 0 || error("n must be non-negative")
n == 0 && return 1
end
fact (generic function with 1 method)
julia> fact(-3)
ERROR: n must be non-negative
julia> fact(0)
1
julia> fact(5)
120
&&,|| のオペランドは最後のものは何でもよいが,それ以外は true, false を返すものでなくてはならない。
julia> 1 && true
ERROR: TypeError: non-boolean (Int64) used in boolean context
julia> true && (1, 2, 3)
(1, 2, 3)
julia> false && (1, 2, 3)
falseビット論理演算子 &, |
&&, || と違い,ショート・サーキット評価は行われない。全てのビットが評価される。
julia> 0b0101 & 0b1110
0x04
julia> 0b0101 | 0b1110
0x0f
繰り返し評価 while, for
while
julia> i = 1;
julia> while i <= 5
println(i)
global i += 1 # global って,何だろう?
end
1
2
3
4
5
for
for ループの外(後)では i は未定義になる。つまり,i のスコープは for ループ内だけである。
julia> for i = 1:5
println(i)
end
1
2
3
4
5
julia> for i in 1:4
println(i)
end
1
2
3
4
in と ∈
julia> for i in [1, 4, 0]
println(i)
end
1
4
0
julia> for s ∈ ["foo","bar","baz"]
println(s)
end
foo
bar
baz
break によるループからの脱出
julia> i = 1;
julia> while true
println(i)
if i >= 5
break
end
global i += 1
end
1
2
3
4
5
julia> for j = 1:1000
println(j)
if j >= 5
break
end
end
1
2
3
4
5
continue によるループの一部分スキップ
julia> for i = 1:10
if i % 3 != 0
continue
end
println(i)
end
3
6
9
複数の for ループの組み合わせ
julia> for i = 1:2, j = 3:4
println((i, j))
end
(1, 3)
(1, 4)
(2, 3)
(2, 4)
例外処理
ArgumentError
BoundsError
CompositeException
DimensionMismatch
DividError
DomainError
julia> sqrt(-1)
ERROR: DomainError with -1.0:
EOFError
ErrorException
InexactError
InitError
InterruptException
InvalidStateException
KeyError
LoadError
OutOfMemoryError
ReadOnlyMemoryError
RemoteException
MethodError
OverflowError
Meta.ParseError
SystemError
TypeError
UndefRefError
UndefVarError
StringIndexError
ユーザが定義できる例外
julia> struct MyCustomException <: Exception end
throw 関数
throw により,明示的に例外を作ることができる。
julia> f(x) = x>=0 ? exp(-x) : throw(DomainError(x, "argument must be nonnegative"))
f (generic function with 2 methods)
julia> f(1)
0.36787944117144233
julia> f(-1)
ERROR: DomainError with -1:
argument must be nonnegative
julia> typeof(DomainError(nothing)) <: Exception
true
julia> typeof(DomainError) <: Exception
false
julia> throw(UndefVarError(:x))
ERROR: UndefVarError: x not defined
julia> struct MyUndefVarError <: Exception
var::Symbol
end
julia> Base.showerror(io::IO, e::MyUndefVarError) = print(io, e.var, " not defined")
error 関数
error 関数は,正常な制御の流れを遮る ErrorException を生成するために使われる。
julia> fussy_sqrt(x) = x >= 0 ? sqrt(x) : error("negative x not allowed")
fussy_sqrt (generic function with 1 method)
julia> fussy_sqrt(2)
1.4142135623730951
julia> fussy_sqrt(-1)
ERROR: negative x not allowed
try/catch 文
julia> try
sqrt("ten")
catch e
println("You should have entered a numeric value")
end
You should have entered a numeric value
julia> sqrt_second(x) = try
sqrt(x[2])
catch y
if isa(y, DomainError)
sqrt(complex(x[2], 0))
elseif isa(y, BoundsError)
sqrt(x)
end
end
sqrt_second (generic function with 1 method)
julia> sqrt_second([1 4])
2.0
julia> sqrt_second([1 -4])
0.0 + 2.0im
julia> sqrt_second(9)
3.0
julia> sqrt_second(-9)
ERROR: DomainError with -9.0:
finally 句
finally 句には例外処理の後始末を書く。
f = open("file")
try
# operate on file f
finally
close(f)
end
タスク(共同関数) yieldto
未
関数定義 -- 伝統的形式
'function' で始まり,関数名,仮引数のタプルが続く。
2 行目から関数の内容を記述する。
一番最後に評価された式の値が戻り値になる。
'return 戻り値' で任意の時点で呼出元へ復帰することもできる。
戻り値がない場合は 'return nothing' とする。
最後の行は 'end'
julia> function f(x, y)
x + y
end
f (generic function with 1 method)
関数の引用
julia> f(1, 3)
4
関数定義 -- 代入文形式
julia> f(x, y) = x + y
f (generic function with 1 method)
右辺は 1 つの式でなければならないが,(begin - end で囲まれた)複合式でもよい。
julia> g(n) = begin # 階乗の計算
ans = 1
for i = 1:n
ans*= i
end
ans
end
g (generic function with 1 method)
無名関数の定義
名前なしの関数を定義し,変数に代入し,変数を関数名のように使うことができる。
よくある使い方は,後に出てくる map 関数で使う方法。
julia> h = x -> x^2 + 2x - 1;
julia> h(3)
14
julia> i = function (x)
x^2 +2x - 1
end
#13 (generic function with 1 method)
julia> i(3)
14
2 個以上の引数を持つ無名関数の定義
julia> (x,y,z)->2x+y-z
#17 (generic function with 1 method)
引数を持たない無名関数の定義
julia> () -> 3
#19 (generic function with 1 method)
関数の戻り値のタイプ指定
julia> function g(x, y)::Int8
return x * y
end;
julia> typeof(g(2, 4))
Int8
関数の引用
julia> f(1, 3)
4
julia> g(5)
120
高階関数 map()
julia> map(round, [1.2, 3.5, 1.7])
3-element Array{Float64,1}:
1.0
4.0
2.0
julia> map(sqrt, [1.2 3.5 1.7])
1×3 Array{Float64,2}:
1.09545 1.87083 1.30384
julia> map(x -> x^2 + 2x - 1, [1.2 3.5 1.7])
1×3 Array{Float64,2}:
2.84 18.25 5.29
タプル
丸括弧 ( ) とカンマ , で構成され,インデックスでアクセスできる。
julia> (1, 1+2)
(1, 3)
julia> (1,) # 要素数が 1 の場合は , が必要
(1,)
julia> () # 空のタプル
()
julia> x = (0.3, "Hello", 6*7)
(0.3, "Hello", 42)
julia> x[1]
0.3
名前付きのタプル
julia> x = (a=2, b=4+6, c="aaa")
(a = 2, b = 10, c = "aaa")
julia> x[1] # インデックスで参照
2
julia> x.b # 名前で参照
10
複数の結果をタプルで返す関数
julia> function foo(a, b)
a+b, a*b # 2 個の値を返す return (a+b, a*b) と書いてもよい
end
foo (generic function with 1 method)
julia> foo(2, 3) # 結果がタプルで戻る
(5, 6)
julia> x, y = foo(2, 3) # タプルを分解して代入する
(5, 6)
julia> x # 1 番目の結果
5
julia> y # 2 番目の結果
6
関数の引数にタプルを使う
julia> minmax(x, y) = (y < x) ? (y, x) : (x, y) # 三項演算子
minmax (generic function with 1 method)
julia> gap((min, max)) = max - min
gap (generic function with 1 method)
julia> gap(minmax(10, 2))
8
引数可変関数
引数の個数が固定ではない関数の定義
julia> bar(a,b,x...) = (a,b,x)
bar (generic function with 1 method)
julia> bar(1, 2)
(1, 2, ())
julia> bar(1, 2, 3)
(1, 2, (3,))
julia> bar(1, 2, 3, 4, 5, 6)
(1, 2, (3, 4, 5, 6))
デフォルト値を持つ引数(オプショナルな引数)
たとえば,以下の関数は x, y の 2 つの引数を持つが,y が与えられなかったときは,それぞれ y = 1 であると解釈される。
julia> function test(x, y=3)
return x * y
end
test (generic function with 2 methods)
julia> test(4, 8) # 4 * 8
32
julia> test(5) # 5 * 3
15
キーワード引数
キーワード引数はセミコロン ';' の後にまとめて定義される。
julia> function test2(x; y=3)
return x + y
end
test2 (generic function with 1 method)
関数を呼び出すときに,キーワード引数を区切るセミコロン ';' はオプショナルである。
julia> test2(2; y=3)
5
以下のように書くのが普通である。
julia> test2(1, y=10)
11
キーワード引数が省略されたときは,デフォルト値が使われる。
julia> test2(3) # test2(3, y=3) と同じ
6
しかし,定義するときにはキーワード名を省略することはできない。
julia> test2(2, 3)
ERROR: MethodError: no method matching
デフォルト値を持たないキーワード引数を定義できるが,使用する場合には実引数を指定しないとエラーになる。
julia> function test3(x; y)
return x^y
end
test3 (generic function with 1 method)
julia> test3(2, y=4)
16
関数の引数のための DO-ブロック構文
julia> A = 1; B = 2; C = 3
3
以下のように書くところを,
julia> map(x->begin
if x < 0 && iseven(x)
return 0
elseif x == 0
return 1
else
return x
end
end,
[A, B, C])
3-element Array{Int64,1}:
1
2
3
以下のように書くことができる。
julia> map([A, B, C]) do x
if x < 0 && iseven(x)
return 0
elseif x == 0
return 1
else
return x
end
end
3-element Array{Int64,1}:
1
2
3
関数の組み立てとパイプ
f, g が関数のとき,(f ∘ g)(引数...) は f(g(引数...)) と同じことを意味する。
対話モードのとき,'∘' は '\circ' で入力できる。
julia> (sqrt ∘ +)(3, 6)
3.0
julia> sqrt(+(3, 6)) # +(3, 6) は 3 + 6 と同じ
3.0
関数の評価結果を次の関数に渡す(パイプする)ことができる。
julia> 1:10 |> sum |> sqrt
7.416198487095663
1:10 は 1 から 10 までの整数ベクトル。それを sum 関数に渡して sum(1:10) = 55が求められる。さらにそれを sqrt 関数に渡して sqrt(55) = 7.416198487095663 が求められる。
今の場合,以下と同じことになる。
julia> (sqrt ∘ sum)(1:10)
7.416198487095663
ブロードキャスティング
'.|>' とパイプ,ドット・ベクトル化構文を合わせると以下のようなこともできる。
julia> ["a", "list", "of", "strings"] .|> [uppercase, reverse, titlecase, length]
4-element Array{Any,1}:
"A"
"tsil"
"Of"
7
ドット・ベクトル化構文 .(ベクトル)
ベクトルの各要素に対して働く関数がある。
julia> A = [1.0, 2.0, 3.0];
julia> sin.(A)
3-element Array{Float64,1}:
0.8414709848078965
0.9092974268256817
0.1411200080598672
julia> f(x, y) = 3x + 4y
f (generic function with 1 method)
julia> f.(pi, A)
3-element Array{Float64,1}:
13.42477796076938
17.42477796076938
21.42477796076938
julia> 3pi + 4 * 1
13.42477796076938
julia> B = [4.0, 5.0, 6.0]
3-element Array{Float64,1}:
4.0
5.0
6.0
julia> f.(A, B)
3-element Array{Float64,1}:
19.0
26.0
33.0
julia> 3 * 1 + 4 * 4
19
ネストされた関数は 1 重のブロードキャスト・ループに融合される。
以下の 3 通りの書き方は,全て同じことである。
julia> X = [1, 2, 3];
julia> sin.(cos.(X))
3-element Array{Float64,1}:
0.5143952585235492
-0.4042391538522658
-0.8360218615377305
julia> broadcast(x -> sin(cos(x)), X)
3-element Array{Float64,1}:
0.5143952585235492
-0.4042391538522658
-0.8360218615377305
julia> [sin(cos(x)) for x in X]
3-element Array{Float64,1}:
0.5143952585235492
-0.4042391538522658
-0.8360218615377305
'ドット・バージョン' に変換 '@.'
'@.' は,式の中にある,全ての関数呼び出し,演算,代入を 'ドット・バージョン' に変換する。
julia> Y = [1.0, 2.0, 3.0, 4.0];
julia> X = similar(Y); # 事前に結果を格納するためのベクトルを用意する
julia> @. X = sin(cos(Y)) # X .= sin.(cos.(Y)) と同じ
4-element Array{Float64,1}:
0.5143952585235492
-0.4042391538522658
-0.8360218615377305
-0.6080830096407656
ドット演算と,関数チェイン '.|>'
ドット演算と,関数チェイン '.|>' を組み合わせると,以下のようなこともできる。
julia> [1:5;] .|> [x->x^2, inv, x->2*x, -, isodd]
5-element Array{Real,1}:
1
0.5
6
-4
true