131
125

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

競技プログラミングにおけるPythonとRustの対応関係まとめ

Last updated at Posted at 2019-09-07

はじめに

競技プログラミングにおいてPythonでよく使用する関数やクラスについて、それらとRustのメソッドやデータ構造との対応をまとめました。
競技プログラミングでPythonからRustへ移行しようとしている人の参考になれば幸いです。

なお、本記事のRustのバージョンは1.15.1を想定しています(2019/09/07時点でのAtCoderのRustのバージョン)。

標準入出力

標準入力

Rustでは std::io::Stdinread_lineメソッドを用いて標準入力を1行単位で受け取ることができます(これはPythonのinput関数と同じですね)。
標準入力のパターンに応じて、受け取った文字列をsplitしたりparseしたりします。
Pythonと比べて、全体にしんどいのでスニペット/テンプレート化しておくとよいでしょう。
なお、高速に標準入力したい場合、StdinLock構造体を使うとよいようです。
参考: Rust の標準入出力は(何も考えないで使うと)遅い - Qiita

ideoneでの実行結果

単一の整数を標準入力する

例: 標準入力から単一の整数を受け取り、 n に束縛する。

Python
n = int(input())
Rust
let n: i64 = {
    let mut line: String = String::new();
    std::io::stdin().read_line(&mut line).unwrap();
    line.trim().parse().unwrap()
};

単一の文字列を標準入力する

例: 標準入力から単一の文字列を受け取り、 s に束縛する。

Python
s = input()
Rust
let s: Vec<char> = {
    let mut line: String = String::new();
    std::io::stdin().read_line(&mut line).unwrap();
    line.trim().chars().collect()
};

Rustでは、文字のVecとして s に文字列を束縛しています(イテレートする際に便利なので)。

定数個の整数を標準入力する

例: 標準入力から空白区切りで3個の整数を受け取り、 それぞれ a, b, c に束縛する。

Python
a, b, c = map(int, input().split())
Rust
let (a, b, c): (i64, i64, i64) = {
    let mut line: String = String::new();
    std::io::stdin().read_line(&mut line).unwrap();
    let mut iter = line.split_whitespace();
    (
        iter.next().unwrap().parse().unwrap(),
        iter.next().unwrap().parse().unwrap(),
        iter.next().unwrap().parse().unwrap()
    )
};

整数の個数が3でない場合、Rustコードの右辺の iter.next().unwrap().parse().unwrap() の個数を整数の個数に合わせる必要があります。

可変個の整数(空白区切り)を標準入力する

例: 標準入力から空白区切りの整数のリストを受け取り、 xs に束縛する。

Python
xs = list(map(int, input().split()))
Rust
let xs: Vec<i64> = {
    let mut line: String = String::new();
    std::io::stdin().read_line(&mut line).unwrap();
    line.split_whitespace()
        .map(|x| x.parse().unwrap())
        .collect()
};

n個の整数(改行区切り)を標準入力する

例: 標準入力から改行区切りの n 個の整数のリストを受け取り、 ys に束縛する。

Python
ys = [int(input()) for _ in range(n)]
Rust
let ys: Vec<i64> = (0..n)
    .map(|_| {
            let mut line: String = String::new();
            std::io::stdin().read_line(&mut line).unwrap();
            line.trim().parse().unwrap()
    })
    .collect();

n行の定数個の整数を標準入力する

例: 標準入力からn行の整数ペアを受け取り、 pairs に(タプルのリストとして)束縛する。

Python
pairs = [tuple(map(int, input().split())) for _ in range(n)]
Rust
let pairs: Vec<(i64, i64)> = (0..n)
    .map(|_| {
        let mut line: String = String::new();
        std::io::stdin().read_line(&mut line).unwrap();
        let mut iter = line.split_whitespace();
        (
            iter.next().unwrap().parse().unwrap(),
            iter.next().unwrap().parse().unwrap()
        )
    })
    .collect();

整数の個数が2でない場合、Rustコードの右辺の iter.next().unwrap().parse().unwrap() の個数を整数の個数に合わせる必要があります。

整数の二次元リストを標準入力する

例: 標準入力から二次元整数リストを受け取り、 mat に(リストのリストとして)束縛する。

Python
mat = [list(map(int, input().split())) for _ in range(n)]
Rust
let mat: Vec<Vec<i64>> = (0..n)
    .map(|_| {
        let mut line: String = String::new();
        std::io::stdin().read_line(&mut line).unwrap();
        line.split_whitespace()
            .map(|x| x.parse().unwrap())
            .collect()
    })
    .collect();

Python, Rust ともにi行目j列目の要素には mat[i][j] でアクセスできます。

標準出力

Rustではprintlnマクロを用いて標準出力します。

ideoneでの実行結果

単一の整数/文字列を標準出力する

例1: 整数 x を標準出力する(末尾に改行文字を含む)。

Python
print(x)
Rust
println!("{}", x);

例2: 文字列 s を標準出力する(末尾に改行文字を含む)。

Python
print(s)
Rust
println!("{}", s);

Rustの sString または &str 型とします。
整数の場合と同一の文です。

文字リストを連結して標準出力する

例: 文字リスト char_list の各文字を連結した文字列を標準出力する(末尾に改行文字を含む)。

Python
print(''.join(char_list))
Rust
println!("{}", char_list.iter().collect::<String>());

Rustの char_listVec<char> 型とします。

定数個の整数/文字列を標準出力する

例: 整数 x, y, z を空白区切りで標準出力する(末尾に改行文字を含む)。

Python
print(x, y, z)
Rust
println!("{} {} {}", x, y, z);

println! の文字列フォーマットを利用します。 文字列を標準出力する場合も同様です。

n個の整数/文字列を空白区切りで標準出力する

例: 整数のリスト xs を空白区切りで標準出力する(末尾に改行文字を含む)。

Python
print(*xs)
Rust
println!(
    "{}",
    xs.iter()
        .map(std::string::ToString::to_string)
        .collect::<Vec<_>>()
        .join(" ")
);

.map(std::string::ToString::to_string).map(|&x| x.to_string()) でも構いません。
xs の要素が文字列ならば .map(std::string::ToString::to_string) は不要です。

n個の整数/文字列を改行白区切りで標準出力する

例: 整数のリスト xs を改行区切りで標準出力する(最終行末尾に改行文字を含む)。

Python
print('\n'.join(map(str, xs)))
Rust
println!(
    "{}",
    xs.iter()
        .map(std::string::ToString::to_string)
        .collect::<Vec<_>>()
        .join("\n")
);

forループで println! をn回呼んでもよいでしょう(ただし、nが大きい場合、実行時間はおよそ10倍になります。この差はPyPyと比べて顕著なので注意してください)。

データ構造

list

Rustではstd::vec::Vecをlistして使う方法を紹介します。

ideoneでの実行結果

listを生成する

例1: 3, 3, 4を要素とするlist a を生成する。

Python
a = [3, 3, 4]
Rust
let mut a = vec![3, 3, 4];

a に対して破壊的操作を行わない場合、 mut は不要です。

例2: 0以上10以下の偶数を2乗したlist b を生成する。

Python
b = [i**2 for i in range(10 + 1) if i % 2 == 0]
Rust
let mut b: Vec<_> = (0..(10_i64 + 1))
    .filter(|&i| i % 2 == 0)
    .map(|i| i.pow(2))
    .collect();

残念ながらRustではリストの内包表記は使えません(サードパーティの cute を使うとリストの内包表記のような記法でvecを作成できるようですが)。

例3: 空のlist c を作成する。

Python
c = []
Rust
let mut empty_list = vec![];

listの要素数を求める

例: list a の要素数を cardinality に束縛する。

Python
cardinality = len(a)
Rust
let cardinality = a.len();

listのi番目の要素を求める

例: list a の2番目(0-indexed)の要素を second_element に束縛する。

Python
second_element = a[2]
Rust
let second_element = a[2];

listをイテレートする

例: list a の要素を先頭から順に1行ずつ標準出力する。

Python
for x in a:
    print(x)
Rust
for &x in &a {
    println!("{}", x);
}

Rustのコードの aVec<i64> 型とします。
Rust で for x in a と書いた場合、所有権が移動してしまい、以降 a を参照できないので注意してください。
また、 for x in &a と書いた場合、 x には a の要素への参照が束縛されることに注意してください(a の要素がプリミティブでないならば、参照を束縛させることになります)。

listに含まれる指定した要素の個数を求める

例: list a に含まれる3の個数を num_of_three に束縛する。

Python
num_of_three = a.count(3)
Rust
let num_of_three = a.iter()
    .filter(|&&x| x == 3)
    .count();

Rustだと少々面倒です。
とはいえ、指定した述語にマッチする要素の個数を求める場合はPythonでも同様のコードになるので、そこまで気にならないと思います。

listのi番目の要素を更新する

例: list a の2番目の要素を3に更新する。

Python
a[2] = 3
Rust
a[2] = 3;

Rust では amut 修飾子付きで宣言されている必要があることに注意です。

listの末尾に要素を追加する

例: list c に 42 を追加する。

Python
c.append(42)
Rust
c.push(42);

listの末尾要素を削除する

例: list b の末尾の要素を削除し、削除した要素を tail に束縛する。

Python
tail = b.pop()
Rust
let tail = b.pop().unwrap();

Rust では unwrap する必要があることに注意です(他のデータ構造も同様)。

dict

Rustではstd::collections::HashMapを使います。

ideoneでの実行結果

dictを生成する

例1: 空のdict scovilles を生成する。

Python
scovilles = {}
Rust
let mut scovilles = std::collections::HashMap::new();

あらかじめ、 use std::collections::HashMap; を宣言すると、 let mut scovilles = HashMap::new(); と書くことができます。

例2: 'a'から'z'をキーとし、それらのアスキーコードを項目とするdict asciicodes を生成する。

Python
asciicodes = {
    chr(ord('a') + i): ord('a') + i
    for i in range(26)
}
Rust
let asciicodes: std::collections::HashMap<_, _> = (0..26)
    .map(|i| {
        let ascii_code = ('a' as u8) + i;
        (ascii_code as char, ascii_code as i64)
    })
    .collect();

Rustではキーと項目のタプルをcollectさせることで、宣言的にdictを作成できます。

dictに項目を設定する

例: dict scovilles に 'habanero' から 100,000 へのマッピングを設定(既に存在する場合は項目を上書き)する。

Python
scovilles['habanero'] = 100_000
Rust
scovilles.insert("habanero", 100_000);

Rustでは scovilles["habanero"] = 100_000; とは書けないです。

dictの要素数を求める

例: dict scovilles の項目数を cardinality に束縛する。

Python
cardinality = len(scovilles)
Rust
let cardinality = scovilles.len();

ある要素がdictのキーとして存在するか判定する

例: dict scovilles のキーに 'reaper' が含まれるならば真、そうでなければ偽を has_reaper に束縛する。

Python
has_reaper = 'reaper' in scovilles
Rust
let has_reaper = scovilles.contains_key(&"reaper");

Rustでは引数は参照型であることに注意してください(strの場合は & 付けなくてもよいですが)。

dictの指定したキーの項目を求める

例1: dict scovilles のキー 'habanero' の項目を habanero に束縛する。

Python
habanero = scovilles['habanero']
Rust
let habanero = scovilles[&"habanero"];

例2: dict scovilles の 'reaper' の項目を reaper に束縛する。ただし、 scovilles のキーに 'reaper' が含まれないならば 0 を束縛する。

Python
reaper = scovilles.get('reaper', 0)
Rust
let reaper = *scovilles.get("reaper").unwrap_or(&0);

キーが存在しない可能性がある場合、Rustでもgetメソッドを使います。getメソッドはOptionを返すのでunwrap_orメソッドを用いるとよいです。

dictをイテレートする

例: dict scovilles のキーと項目のペアを空白区切りで1行ずつ出力する。

Python
for k, v in scovilles.items():
    print(k, v)
Rust
for (&k, &v) in &scovilles {
    println!("{} {}", k, v);
}

dictから項目を削除する

例: dict scovilles からキー 'habanero' とそれに対応する項目を削除する。

Python
scovilles.pop('habanero')
Rust
scovilles.remove(&"habanero");

set

Rustではstd::collections::HashSetを使います。
setとHashSetの関係はdictとHashMapの関係とほぼ同じです。

ideoneでの実行結果

setを生成する

例1: 空のset s を生成する。

Python
s = set()
Rust
let mut s = std::collections::HashSet::new();

例2: 0以上10未満の偶数のset evens を生成する。

Python
s = set()
Rust
let evens: std::collections::HashSet<_> = (0..10)
    .filter(|&i| i % 2 == 0)
    .collect();

setに要素を追加する

例: set s に 8 を追加する。

Python
s.add(8)
Rust
s.insert(8);

setの要素数を求める

例: set s の要素数を cardinality に束縛する。

Python
cardinality = len(s)
Rust
let cardinality = s.len();

ある要素がsetに含まれるか判定する

例: set s に 1 が含まれるならば真、そうでなければ偽を has_one に束縛する。

Python
has_one = 1 in s
Rust
let has_one = s.contains(&1)

setをイテレートする

例: set s の要素を空白区切りで1行ずつ出力する。

Python
for x in s:
    print(x)
Rust
for &x in &s {
    println!("{}", x);
}

setから要素を削除する

例: set s から 8 を削除する。

Python
s.remove(8)
Rust
s.remove(&8);

ヒープ

ここでは、(Pythonの heapq に合わせて)Minヒープとして扱う方法を説明します。Rustではstd::collections::BinaryHeapを使います。

ideoneでの実行結果

空のヒープを生成する

例: 空のヒープ q を生成する。

Python
import heapq
q = []
Rust
let mut q = std::collections::BinaryHeap::new();

ヒープに要素を追加する

例: ヒープ q に3, 1, 4 をこの順で追加する。

Python
heapq.heappush(q, 3)
heapq.heappush(q, 1)
heapq.heappush(q, 4)
Rust
q.push(-3);
q.push(-1);
q.push(-4);

BinaryHeapはMaxヒープなので、符号を反転しています。
タプルを要素する場合でも、辞書式順序で比較するので、適宜符号を反転すればよいです
(Rust 1.15.1(2019/09/07時点でのAtCoderのRustのバージョン)では、std::cmp::Reverse
は使用できないので注意してください)。

ヒープの最小要素を求める

例: ヒープ q の最小要素を top に束縛する。

Python
top = q[0]
Rust
let top = -(*q.peek().unwrap());

Rustの方は符号を反転した要素を追加しているので、符号を反転して元に戻しています。

ヒープが空か判定する

例: ヒープ q が空ならば真、そうでなければ偽を is_empty に束縛する。

Python
has_element = q == []
Rust
let is_empty = q.is_empty();

ヒープの最小要素を取り出す

例: ヒープ q の最小要素を削除し、削除した要素を popped に束縛する。

Python
popped = heapq.heappop(q)
Rust
let popped = -q.pop().unwrap();

popメソッドが返す値は参照型ではないので、参照外しは不要であることに注意してください。

defaultdict

Rustではstd::collections::HashMapをdefaultdictとして使います。
HashMapからstd::collections::hash_map::Entryを取得し、Entryのor_insertメソッドを用いてデフォルト値を得られるようにします。

ideoneでの実行結果

defaultdictを生成する

例: デフォルト値が0であるdefaultdict scovilles を生成する。

Python
import collections
scovilles = defaultdict(int)
Rust
let mut scovilles = std::collections::HashMap::new();

scovilles はただのHashMapなのでdefaultdictではないですが、項目を取得する際に工夫することでdefaultdictのように扱えます。

defaultdictに項目を設定する

例: defaultdict scovilles に 'reaper' から 2,000,000 へのマッピングを設定(既に存在する場合は項目を上書き)する。

Python
scovilles['reaper'] = 2_000_000
Rust
scovilles.insert("reaper", 2_000_000);

defaultdictの指定したキーの項目を求める

例: defaultdict scovilles のキー 'habanero' の項目を habanero に束縛する。ただし、 scovilles にキー 'habanero' が存在しない場合、
scovilles に 'habanero' から 0(デフォルト値) へのマッピングを設定した上で habanero にはデフォルト値である0を束縛する。

Python
habanero = scovilles['habanero']
Rust
let habanero = *scovilles.entry("habanero").or_insert(0);

Counter

defaultdict同様、Rustではstd::collections::HashMapをCounterとして使います。残念ながらPythonのように楽はできないです。

ideoneでの実行結果

Counterを生成する

例: リスト [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5] の各整数に関するCounter c を生成する。

Python
import collections
c = collections.Counter([3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5])
Rust
let mut c = std::collections::HashMap::new();
for &i in &vec![3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5] {
    *(c.entry(i).or_insert(0)) += 1;
}

ここでもEntryの or_insert が役立ちます。

指定したキーのカウントを求める

例: Counter c の5のカウントを num_of_five に束縛する。

Python
num_of_five = c[5]
Rust
let num_of_five = *c.get(&5).unwrap_or(&0);

dictと同様です。

指定したキーのカウントを増やす

例: Counter c の3のカウントを57増やす

Python
c[3] += 57
Rust
*(c.entry(&3).or_insert(0)) += 57;

or_insert を用いることで加算代入できます。

deque

Rustではstd::collections::VecDequeを使います。

ideoneでの実行結果

空のdequeを生成する

例: 空のdeque d を生成する。

Python
import collections
d = collections.deque()
Rust
let mut d = std::collections::VecDeque::new();

dequeの先頭に要素を追加する

例: deque d の先頭に 4 を追加する。

Python
d.appendleft(4)
Rust
d.push_front(4);

dequeの末尾に要素を追加する

例: deque d の末尾に 2 を追加する。

Python
d.append(2)
Rust
d.push_back(2);

dequeの要素数を求める

deque d の要素数を cardinality に束縛する

Python
cardinality = len(d)
Rust
let cardinality = d.len();

dequeの先頭要素を求める

例: deque d の先頭要素を head に束縛する。

Python
head = d[0]
Rust
let head = *d.front().unwrap();

dequeの末尾要素を求める

例: deque d の末尾要素を tail に束縛する。

Python
tail = d[-1]
Rust
let tail = *d.back().unwrap();

dequeの先頭要素を削除する

例: deque d の先頭要素を削除し、削除した要素を popped_head に束縛する。

Python
popped_head = d.popleft()
Rust
let popped_head = d.pop_front().unwrap();

dequeの末尾要素を削除する

例: deque d の末尾要素を削除し、削除した要素を popped_tail に束縛する。

Python
popped_tail = d.pop()
Rust
let popped_tail = d.pop_back().unwrap();

イテレート

Pythonのコードではitertoolsモジュールとfunctoolsモジュールがインポートされているとして説明します。

Python
import itertools
import functools

ideoneでの実行結果

reversed

例: 整数リスト xs の順序を逆転したリストを rev_xs に束縛する。

Python
rev_xs = list(reversed(xs))
Rust
let rev_xs: Vec<i64> = xs.iter().map(|&x| x).rev().collect();

.map(|&x| x).copied() の代用です(Rust 1.15.1(2019/09/07時点でのAtCoderのRustのバージョン)では、Iteratorにcopiedメソッドがないため)。

accumulate

例: 整数リスト xs の累積和のリストを acc に束縛する。

Python
acc = list(itertools.accumulate(xs))
Rust
let acc: Vec<_> = xs.iter()
    .scan(0, |state, &x| { *state += x; Some(*state) })
    .collect();

zip

例: 整数リスト xsys から要素を集めたリストを xys に束縛する。

Python
xys = list(zip(xs, ys))
Rust
let xys: Vec<_> = xs.iter().map(|&x| x).zip(ys.iter().map(|&x| x)).collect();

map

例: 整数リスト xs の各要素を2乗したリストを sqs に束縛する。

Python
sqs = list(map(lambda x: x**2, xs))
Rust
let sqs: Vec<_> = xs.iter().map(|&x| x.pow(2)).collect();

filter

例: 整数リスト xs から奇数の要素を抽出したリストを odds に束縛する。

Python
odds = list(filter(lambda x: x % 2 == 1, xs))
Rust
let odds: Vec<_> = xs.iter().filter(|&&x| x % 2 == 1).map(|&x| x).collect();

reduce

例: フィボナッチ数列 [0, 1, 1, 2, 3, 5, 8, ...] の第5項(0-indexed)を fib5 に束縛する。

Python
fib5, _ = functools.reduce(
    lambda p, _: (p[0] + p[1], p[0]),
    range(4),
    (1, 0)
)
Rust
let (fib5, _) = (0..4).fold(
    (1, 0),
    |(p, pp), _| (p + pp, p)
);

Pythonではlambda関数の引数に対してアンパック代入を適用できませんが、Rustではそれが可能です。添字アクセスしなくて済むのは嬉しいですね。

max/min

例1: 整数リスト xs の最大値を x_max に束縛する。

Python
x_max = max(xs)
Rust
let x_max = *xs.iter().max().unwrap();

例2: 整数リスト zs の最小値を z_min に束縛する。ただし、 zs が空ならば0を z_min に束縛する。

Python
z_min = min(zs, default=0)
Rust
let z_min = *zs.iter().max().unwrap_or(&0);

例3: 整数リスト xs に含まれる要素のうち、2で割った余りが最小となる要素を x_argmin に束縛する。ただし、そのような要素が複数存在する場合、リストの先頭に近い要素を x_argmin に束縛する。

Python
x_argmin = min(xs, key=lambda x: x % 2)
Rust
let x_argmin = *xs.iter().min_by_key(|&&x| x % 2).unwrap();

sum

例: 整数リスト xs の各要素の和を s に束縛する。

Python
s = sum(xs)
Rust
let s: i64 = xs.iter().sum();

all/any

例1: 整数リスト xs の要素がすべて奇数ならば真、そうでなければ偽を is_all_odd に束縛する。

Python
is_all_odd = all(x % 2 == 1 for x in xs)
Rust
let is_all_odd = xs.iter().all(|&x| x % 2 == 1);

例2: 整数リスト xs の要素に偶数が存在するならば真、そうでなければ偽を does_exist_even に束縛する。

Python
does_exist_even = any(x % 2 == 0 for x in xs)
Rust
let does_exist_even = xs.iter().any(|&x| x % 2 == 0);

enumerate

例: 整数リスト xs から各要素のインデックス(0-indexed)とその要素をペアにしたリストを indexed_xs に束縛する。

Python
indexed_xs = [(i, x) for i, x in enumerate(xs)]
Rust
let indexed_xs: Vec<_> = xs.iter().map(|&x| x).enumerate().collect();

Rustではインデックスの開始番号を指定できないことに注意してください。例えば、1-indexedにしたい場合は、1スタートのrangeオブジェクトとzipさせればよいです。

sorted

例: 整数リスト xs を昇順ソートしたリストを sorted_xs に束縛する。

Python
sorted_xs = sorted(xs)
Rust
let sorted_xs: Vec<_> = {
    let mut tmp_xs = xs.clone();
    tmp_xs.sort();
    tmp_xs
};

Rustの標準ライブラリには非破壊的なソートメソッドは存在しません。

range

例1: 0以上10未満の整数のリストを ps に束縛する。

Python
ps = list(range(10))
Rust
let ps: Vec<_> = (0..10).collect();

例2: 1以上10未満の整数のリストを qs に束縛する。

Python
qs = list(range(1, 10))
Rust
let qs: Vec<_> = (1..10).collect();

なお、 Rust 1.15.1(2019/09/07時点でのAtCoderのRustのバージョン)では、rangeのstepをカスタムするのは(スマートには)できないです。

スライス

例1: 整数リスト xs の先頭から3番目まで(0-indexed, exclusive)の要素から成るリストを heads に束縛する。

Python
heads = xs[:3]
Rust
let heads = xs[..3].to_vec();

例2: 整数リスト xs の3番目から(0-indexed, inclusive)末尾までの要素から成るリストを tails に束縛する。

Python
tails = xs[3:]
Rust
let tails = xs[3..].to_vec();

文字列

標準入出力でも述べた通り、Rustでは文字列を Vec<char> として扱うと使い勝手がよいです。
Vec<char> として扱えば、listで述べた操作が可能なので、i文字目の取得や特定の文字のカウントが可能です。

ここでは、数字の文字を整数に変換する方法と整数を文字列に変換する方法についてのみ述べます。

ideoneでの実行結果

int

例: 文字 '1' を整数1として x に束縛する。

Python
x = int('1')
Rust
let x = '1'.to_digit(10).unwrap() as i64;

'1' as i64 だと x は49('1'のASCIIコード)になることに注意してください。

str

例: 整数42を文字列として s に束縛する。

Python
s = str(42)
Rust
let y: Vec<_> = 42.to_string().chars().collect();

Rustでは文字のリストとして s に束縛しています。
String型として束縛したいならば、単に let y = 42.to_string(); でよいです。

数学

ideoneでの実行結果

abs

例: 整数 x の絶対値を a に束縛する。

Python
a = abs(x)
Rust
let a = x.abs();

gcd

例: 整数 p, q の最大公約数を g に束縛する。

Python
import fractions
p = 12
q = 18
g = fractions.gcd(p, q)

AtCoderのPythonバージョンは3.4.3なので、math.gcdではなくfractions.gcdを用いています。

Rust
let g = {
    fn gcd(x: i64, y: i64) -> i64 {
        if y == 0 {
            x
        } else {
            gcd(y, x % y)
        }
    }
    gcd(p, q)
};

残念ながら、Rustの標準ライブラリにはgcdはありません。

pow

例1: 正の整数 q, n について、 qn 乗を z に束縛する。

Python
z = q**n
Rust
let z = q.pow(n);

例2: 整数 q の $10^9 + 5$ 乗に対する $10^9 + 7$ の剰余を r に束縛する。

Python
r = pow(q, 10**9 + 5, 10**9 + 7)
Rust
let r = {
    fn mod_pow(x: i64, y: i64, z: i64) -> i64 {
        if y == 0 {
            1
        } else {
            let h = mod_pow(x, y / 2, z);
            let res = (h * h) % z;
            if y % 2 == 0 {
                res
            } else {
                (res * x) % z
            }
        }
    }
    mod_pow(q, 1_000_000_005, 1_000_000_007)
};

Rustのpowは剰余をとるべき乗を求められないので、自力でダブリングしています。

sqrt

例: 正の整数 q の平方根を s に束縛する。

Python
import math
s = math.sqrt(q)
Rust
let s = (q as f64).sqrt();

i64にはsqrtメソッドはないので、f64にキャストします。

bisect

RustのVecにはbinary_searchメソッドがありますが、同一の要素が複数存在する場合、得られるインデックスは不定なので、競技プログラミングにおいて使うのは厳しいです。
仕方ないので、自力で二分探索します。

ideoneでの実行結果

bisect_left

例: 昇順ソートされている整数のリスト x から、5以上の要素のうち、最小のインデックスを i に束縛する。

Python
i = bisect.bisect_left(x, 5)
Rust
fn bis<P>(ok: i64, ng: i64, p: P) -> i64
    where P: Fn(i64) -> bool {
    let mid = (ok + ng) / 2;
    if (ok - ng).abs() == 1 {
        ok
    } else if p(mid) {
        bis(mid, ng, p)
    } else {
        bis(ok, mid, p)
    }
}
let i = bis(x.len() as i64, -1, |i| x[i as usize] >= 5);
println!("i = {}", i);

Rustの bis は二分探索を行う関数です(所謂めぐる式)。
i64に対して二分探索を行うので、Vecの要素にアクセスする際はusizeにキャストしています。

bisect

例: 昇順ソートされている整数のリスト x から、5より大きい要素のうち、最小のインデックスを j に束縛する。

Python
j = bisect.bisect(x, 5)
Rust
fn bis<P>(ok: i64, ng: i64, p: P) -> i64
    where P: Fn(i64) -> bool {
    let mid = (ok + ng) / 2;
    if (ok - ng).abs() == 1 {
        ok
    } else if p(mid) {
        bis(mid, ng, p)
    } else {
        bis(ok, mid, p)
    }
}
let j = bis(x.len() as i64, -1, |i| x[i as usize] > 5);
println!("j = {}", j);

Rustのコードは bis のクロージャの不等号から等号が外れています。

おわりに

比較してみると、やはりPythonの方がコーディングは楽ですが、Rustもそれほど悪くないかなと感じます
(標準ライブラリがやや貧弱なのがつらいですが)。
個人的には、Rustのクロージャのパターンマッチがお気に入りです。

131
125
7

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
131
125

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?