RubyのArrayのunshiftはpushと比べて同じだったり遅かったりする
最初に
自分の整理のためにRubyのArray
のpush
とunshift
の速さについて書く。
結論からいうと、Array#unshift
は、push
と同じ並の速さをだすこともあれば、格段に遅くなることもある。
他の言語だと遅いが、RubyのArray#unshiftは速い
C++のvector
にはpush_back
とpop_back
という末尾への追加と取り出しはあるが、
先頭への追加・取り出しのpush_front
とpop_front
はない。
これはC++のvector
が、末尾への追加・取り出しは高速にできるが、先頭への追加・取り出しは容易にできないデータ構造だから、実装されてないと考えられる。
これは、他の言語でも似たようなことが言えて、JavaScriptやPythonでの基本的な配列(≒リスト)では先頭への追加・取り出しと末尾への追加・取り出しの両方が用意されているのが、後者が明らかに遅いようだ。
しかし、Rubyの末尾追加であるArray#unshift
は、必ずしも遅いわけではない。(遅いケースもあるのだが)
2019/07 RubyのArray#unshiftが速すぎる件と償却解析
実際、こういった記事を読んだり、経験などから、
Rubyの末尾追加であるArray#unshift
(prepend
)は、Array#push
(append
)と同等のスピードである、と感じていた。
すごく単純な時間計測をするとunshift
とpush
を比べてみると、同等のスピードであることがわかる。
require 'benchmark' n = 10**5 Benchmark.bm(10) do |r| r.report("empty-loop"){ |i| a = []; n.times{ } } r.report("push "){ |i| a = []; n.times{ a.push(0) } } r.report("unshift "){ |i| a = []; n.times{ a.unshift(0) } } end # user system total real # empty-loop 0.002462 0.000000 0.002462 ( 0.002460) # push 0.005110 0.000000 0.005110 ( 0.005112) # unshift 0.005339 0.000000 0.005339 ( 0.005341)
上記の例では、10**5(100,000)個の要素を追加するのに、末尾追加でも先頭追加でも0.005秒かかっている。
同じループ数で空のループが0.0025秒で、push
でもunshift
でもO(1)の時間計算量であるといえそう。
ところで、ここで思うのは、単純な比較だが、要素を追加していく処理とループ処理がザックリ0.0025秒ほどで、 ループ処理は意外にけっこう重たい処理なように感じる。
こういうわけで、自分はpush
とunshift
は常にO(1)の時間計算量であると思っていた。(これは誤りであった。)
RubyのArrayのunshiftは、やっぱり遅い一面がある。
競技プログラミングの「競プロ典型 90 問」の44問目の問題を解いて、unshift
は常に速いとは限らないことがわかった。
下記の例では、a[0] = 0
という破壊的操作を加えた上に、同じように10**5個の要素を追加している。
しかし、明らかにunshift
が遅い。
require 'benchmark' n = 10**5 Benchmark.bm(8) do |r| r.report("= & push "){ |i| a = []; n.times{ a[0] = 0; a.unshift(0) } } r.report("= & unshift "){ |i| a = []; n.times{ a[0] = 0; a.push(0) } } end # user system total real # = & push 0.006590 0.000000 0.006590 ( 0.006592) # = & unshift 2.215506 0.000655 2.216161 ( 2.216260)
push
の方が0.0065秒、unshift
の方が2.2秒。
単純な比較ではpush
とunshift
は同等の速さであったが、
a[0] = 0
と破壊的操作を1つ加えるだけでunshift
が100倍以上も遅い結果となった。
push
は常にO(1)のようだが、unshift
は破壊的操作が加わると計算量がO(n)とかに変わるようでかなり遅くなっている。
最後に
Array#unshiftは、pushと同じ並のO(1)の速さをだすこともあれば、異常に遅い速さになることもなることがわかった。
気軽にunshift
を使うときは、破壊的操作をしてないか、遅くなってないかに気を配る必要がありそうだ。
最後になりますが、ruby-jpやTwitterで、mameさん、climpetさん、kuma kumaさん、tompngさん、superrino130さん等から、アドバイスや意見を貰え、とても参考になり感謝してます。
参考リンク
RubyでABC201(マイナビプログラミングコンテスト2021)のE問題までの解説
最初に
今週あたりは夜9時あたりに寝てたが、
頑張ってAtCoderのABC201ABC201(マイナビプログラミングコンテスト2021)に参加した。
コンテスト中はD問題まで解けて、E問題までACできたので、E問題まで簡単に参加記ないし解説を駆け足で書いていく。
A - Tiny Arithmetic Sequence
a = gets.to_s.split.map{ |e| e.to_i }.sort puts (a[2] - a[1] == a[1] - a[0]) ? "Yes" : "No"
タブを開きすぎててコンテストに支障がありそうだったから、タブを削除。
ちょっと出遅れたけど、それでも2分ほどで解けたので悪くない。
Rubyにしては入力が冗長なのは、Crystalに移植しやすいようにしている。
そして、入力とともにソート。
昇順でも降順でもソートした数列の差が等しいかを見るだけ。
B - Do you know the second highest mountain?
A問題は数が3つだけで、数値だけのソートで良かった。
B問題は高さを指定して、ソートすると楽。
Rubyではこういうブロックを使うとき、sort
ではなく、sort_by
を使う。
ちゃんと高さをto_i
で数値変換した上でsort_by
で比較しておかないと、文字列で比較してWAになってしまう。
n = gets.to_s.to_i m = Array.new(n){ gets.to_s.split }.sort_by{ |name, h| h.to_i } puts m[-2][0]
to_i
を付け忘れる凡ミスで1WAとしてしまい、もったいない。
C - Secret Number
最初に場合分けを考えていたがすごく大変そうでミスしやすそうな解法で、ミスしない自信もなく書くのが大変そうで紙で数式を書いたりしながら考えいた。
考えていたところ、数が全体的に小さいから、全探索などで行けそうだとひらめいた。
s = gets.to_s.chomp o = s.count("o") q = s.count("?") a = ((1..o).to_a + (-q..-1).to_a).repeated_permutation(4).to_a p a.count{ |d| (1..o).all?{ |e| d.include?(e) } }
これはコンテスト後に、整理して通したコード。
x
は使わないので除外して、o
と?
だけに集中して考えると見通しが良い。
何の数字がo
やq
になっているかは重要ではなく、o
や?
の種類の数が重要。
まず、String#count
で、数を数える。o
と?
の種類数をo
とq
という変数に置いた。
(1..o).to_a
と(-q..-1).to_a
で、それぞれo
を1からoまでの数、q
を-qから-1までの数として適当に置き直した。
ここで、o
と?
をそれぞれ正の数と負の数に置き換えたが、元が異なる数字なので、重複しないことが重要。
そのあと、Array#repeated_permutation
で4を指定して、o
と?
の数字を使った4文字の暗号を全探索するために全て列挙する。
配列a
には、可能性のある全ての暗号が入っている。※最初から可能性のないx
は除いている。
この可能性のある暗号の中で、条件に当てはまるものだけをcount
で数えていく。
条件にあてはまるかどうかは、all?
でo
の数字が全てつかわれているかを見る。
D - Game in Momotetsu World
こういう感じの必勝法を考えるときは、ゴールから逆算して後ろから考える。
2人で交互に1から3個の連続した数値をいっていって最初に21を言った方が負け、みたいなゲームの必勝法を考えるときも、後ろから考える。
「もしここからスタートしてたらいくつの点差になるか」をゴールから逆算して後ろから考える。
考えながらも雰囲気で解いた感じのところがあるので、嘘解法でない自信がちょっとないが、簡単に解説を書いていく。
右か下に動いていくので、必ず1番右の部分で終わる。ここがゴール。
そして、高橋君と青木君が交互に動かすが、どちらに影響するマスかは市松模様となることがわかる。
i + j
の偶奇でわかれる市松模様で、プラスマイナスは逆の意味になる。
つまり、青木君にとっての+-
は、高橋君にとっての-+
になる。
i + j
の偶奇で+-
を反転させるとよさそう。
また、+-
がポイントに与える影響を考えると、+1
, -1
となる。
Rubyでは、文字の配列を作ると重たくなることがあり、今回は要素数が多かったので、String#bytes
ですぐ数値の配列を作りにいっている。
また、^
が排他的論理和(xor)の演算子であり、これを使うと1
と-1
の振り分けが容易になる。
なお、String#bytes
は、バイトの数値(ここでは文字コードと同じ)に変換するメソッドで、'+'
は43
, '-'
は45
に変換される。
自分の実装だと、1行か1列のとき、つまりH == 1 || W == 1
のときにコーナーケースとなるようなので、別で実装した。
サンプルにH == 1 && W == 1
のケースを置いてくれてありがたい。
H == 1 && W == 1
のときは、最初の高橋君が動かせずポイントが変わらないので、"Draw"
を出力して即終了。
また、W == 1
のときは、transpose
で二重配列の縦横を入れ替える等して、H == 1
としてまとめて処理するようにした。
先に、1番後ろの列と行から始めるケースだと、両者選択の余地がないので、単純に後ろから累積和を作る要領で、その地点から始めたときのポイント差を求めた。
そして、それ以外のケースでは、高橋君が動かすときは右と下でポイント差を最大化できる方に動くのでmax
メソッドで判定して大きい方を取り、反対に青木君だとポイント差が逆のマイナス方向に動くようにmin
メソッドで判定して小さい方を取る形で、累積和を求めるようなDPをした。
$debug = false h, w = gets.to_s.split.map{ |e| e.to_i } if h == 1 && w == 1 puts "Draw" exit end m = Array.new(h){ |i| gets.to_s.chomp.bytes.map.with_index{ |e, j| ((i + j).even? ^ (e == 43)) ? 1 : -1 } } if h == 1 || w == 1 m = m.transpose if w == 1 w = [w, h].max h = 1 end (w - 1).downto(1){ |j| m[-1][j - 1] += m[-1][j] } (h - 1).downto(1){ |i| m[i - 1][-1] += m[i][-1] } if h == 1 puts ["Draw", "Takahashi", "Aoki"][m[0][1] <=> 0] exit end puts m.map{ _1.join(" ") } if $debug (h-2).downto(0) do |i| (w-2).downto(0) do |j| if (i + j).even? m[i][j] += [m[i + 1][j], m[i][j + 1]].max else m[i][j] += [m[i + 1][j], m[i][j + 1]].min end end end puts m.map{ _1.join(" ") } if $debug mm = [m[0][1], m[1][0]].max puts ["Draw", "Takahashi", "Aoki"][mm <=> 0]
puts ["Draw", "Takahashi", "Aoki"][m[0][1] <=> 0]
出力のこの部分は、普段はこのように自分は書かないけど、本質に関係ない部分を短くするため、書き直した。
<=>
は大小判定で-1
, 0
, 1
を返すメソッドで、配列に3要素のどれかを取る形になる。
実際は、サンプル1で、書きながら考えた。
0 | 1 | 2 |
---|---|---|
T | A | |
T | A | T |
A | T | A |
↓
+1
だと高橋君に有利なようにポイントが大きくなる。
0 | 1 | 2 |
---|---|---|
-1 | +1 | |
+1 | +1 | +1 |
+1 | -1 | +1 |
↓
0 | 1 | 2 |
---|---|---|
2 | 3 | |
-1 | 2 | 2 |
-1 | 0 | 1 |
右下から累積和をとっていく。この表が作れるように頑張る。
(考え方は正しいと思うが、ちょっとやっぱりミスってる気がしてる気が。コーナーケースができるのが変な気がする)
E - Xor Distances
木の問題に苦手意識があって飛ばしてF問題を最初に考えてたが、こっちを頑張った方が良さそうだった。
こっちは、典型問題や過去問の組み合わせで解けるような感じだった。
ある頂点から全ての頂点に対するxorのdistを求める。要素数Nのxorのdistという距離が入った配列を作る。
これは木のBFSやDFSといった典型のやり方で距離を求めるところを、+
から^
に変えて、xor距離なるものを求めるようにする。
そうすると、xorの二重和というABC147のD - Xor Sum 4という問題に帰着できる。ここ、論理が少し飛躍してるかも。
mod = 10**9 + 7 n = gets.to_s.to_i g = Array.new(n){ [] } (n - 1).times do s, t, w = gets.to_s.split.map{ |t| t.to_i } s -= 1 t -= 1 g[s] << [t, w] g[t] << [s, w] end d = [-1] * n s = 0 d[s] = 0 q = [s] while ( v = q.pop ) t = d[v] g[v].each do |(u, c)| next if d[u] >= 0 d[u] = t ^ c q << u end end # ここで、zero based originで0番目の頂点からのxor距離が d に入った。 # ABC147 D - Xor Sum 4 ans = (0..60).sum do |i| c = d.sum{ |k| k[i] } c * (n - c) << i end puts ans % mod
ABC147のD - Xor Sum 4に帰着できることは正しいので、最初にこの問題を解けるようになった方がいい。
ABC147のD - Xor Sum 4の解説は、けんちょんさんの解説がわかりやすかった。
最後に
駆け足で書きましたが、ABC201(マイナビプログラミングコンテスト2021)の解説でした。
Rubyと違いのあるCrystalの文字列の注意点
最初に
Crystal と Ruby はよく似た言語だが、様々な点で違いがある。
Ruby から Crystal の文字列を扱うときの注意点を書いてみる。
Crystalには文字がある
Ruby には文字列という概念しかないが、Crystal には文字と文字列という概念がある。
C言語などを学習したことがある人にとっては馴染み深いだろうが、
文字と文字列で区別するとき、
- 文字 …… 1文字で
'
で囲む。 - 文字列 …… 0文字以上で
"
で囲む。
という違いがある。
Ruby の文字列をシングルクォートで書いてると、Crystal に移植するとき、"
に変更する必要があって面倒。
Crystalの文字列はイミュータブル
Ruby の文字列は、ミュータブルなもので、破壊的メソッドで破壊的な変更をすることができる。
しかし、Crystalの文字列は、イミュータブルで、破壊的メソッドはない。
イミュータブルにすると速くなることがあったり、コードとしての安全性が増す等のメリットがあるようだ。
なお、Python や JavaScript などの言語で、文字列はイミュータブルものである。
Ruby も昔は、Ruby 3.0では文字列はイミュータブルなものに変更しようという動きがあったが、
結局、後方互換性に大きな問題があるということでなくなった。
なお、後方互換性のない大きな変更をしたところで、大きなメリットがないという批判もあった。
具体的にできないこと
str = "Hello!" p str[0] # => 'H' p str[2..3] # => "ll"
Crystal は[]
で文字や文字列をとることができるが、
Crystalの文字列はイミュータブルなので[]=
の形で文字列の中の文字を変更することができない。
Crystalの文字と文字列の結合
文字と文字列は、足すことができる。
p "Hello" + '!' # => "Hello!" p '!' + "Hello" # => "!Hello"
しかし、文字と文字は足すことが、できない。
p '!' + '?' # Error: no overload matches 'Char#+' with type Char # # Overloads are: # - Char#+(str : String) # - Char#+(other : Int)
このエラー文を見てわかるが、文字にはInt
型の数値を足すことができる。
p 'b' + 1 # => 'c' p 'b' - 1 # => 'a'
これは、Ruby にはない機能だ。競プロとかだと、ちょっと便利かもしれない。
Crystalの文字と文字列の比較
p 'a' == "a" # => false p 'a' == 97 # => false p 'a'.ord # => 97
Crystal の文字と文字列は足すことができたが、同じだろうと思うものでも比較をするとfalse
を返してくる。
このあたりは非自明で、注意ポイントだと捉えている。
Crystal の文字は、倍にできない。
RubyでもCrystalでも、文字列は倍などにできる。
p "a" * 2 # => "aa"
しかし、Crystalの文字に対して、*
を使えないので注意が必要。
'a' * 2 # error in line 1 # Error: undefined method '*' for Char
実行しようとすれば、定義されてないので、Charに対して*
は未定義というエラーで怒られる。
String#chars
Ruby のString#chars
は、文字列から文字の配列を作るだけでなく、ブロックで文字を回すこともできる。
しかし、CrystalのString#chars
は、文字の配列を作るだけで、ブロックを取ることはできない。
"str".chars{ |c| p c } # Error: 'String#chars' is not expected to be invoked with a block, but a block was given
Ruby でも、 Crystal でも、文字列の文字を回したくなったら、each_char
を使おう。
"str".each_char{ |c| p c }
Crystal の全体的な方針としてエイリアスは作らない方針があり、ブロックをとって回すメソッドはeach_
を接頭辞(prefix)でつけると考えてよい。
なお、Crystal のchars
もeach_char
も、要素は文字列Stgring
ではなく、文字Char
となることに注意。
p typeof("str".chars) # => Array(Char)
String#bytes
Ruby の String#bytes
は、文字列からバイトの配列を作るだけでなく、ブロックでバイトを回すことができる。
こちらもchars
同様、Crystal ではbytes
でブロックをとって回すことはできない。
ブロックをとって回すときは、each_byte
を使う。
Ruby でも、chars
やbytes
でブロックをとって回すのは少しお行儀が悪いので、each_char
やeach_byte
を使いましょうという話。
また、Crystal の返す配列の要素は、Int32
などではなく、Int8
型である点に注意。
Crystalは、三単現
文字列に限った話ではないが、Crystal は三単現(三人称・単数形・現在形)で統一する方向性である。
Ruby でのString#start_with?
やString#end_with?
は、CrystalではString#starts_with?
やString#ends_with?
である。
JavaScript でも同名の三単現のメソッドがあるので、JavaScript
使いは馴染みやすそうである。
最後に
ザーッと Ruby から Crystal の文字列を扱うときの注意点を書いてみたが、いかがでしたでしょうか?
【Heroku】Error: vue-loader requires @vue/compiler-sfc to be present in the dependency tree.【Rails&yarn】
最初に
git push heroku main
とコマンドを打って、herokuにpushした。
そうすると、次のようなエラーがでた。
Error: vue-loader requires @vue/compiler-sfc to be present in the dependency tree.
このエラーをググって出てきた解決策だと、解決しなかったのでブログに書くことにした。
巷の解決策
「バージョンを変更するといい」みたいな解決策がヒットしたが、これだとうまくいかなかった。
実際のエラーの解決
"@vue/compiler-sfc"
が必要らしい。
package.json
を見ると、何故か"devDependencies"
の中に記載されていた。
devはdevelopment(開発)の略で、開発環境だけで使われる想定なのだろう。
これを"dependencies
の方に移してやることにした。
{ "name": "application-name", "private": true, "dependencies": { "vue": "^3.0.7", "vue-loader": "16.0.0-rc.0", "vue-template-compiler": "^2.6.12", "@vue/compiler-sfc": "^3.0.11", "vuex": "^3.6.2" }, "version": "0.1.0", "devDependencies": { "webpack-dev-server": "^3.11.2" } }
それから、再びyarnでインストールし直すところから。
yarn upgrade
して、git add .
&git commit -m "@vue/compiler-sfcを本番環境に"
として、再びgit push heroku main
。
これでエラーはでなくなった。めでたし、めでたし。
改めて見てみると
package.json
を見慣れてなくて、dependency tree
が具体的に何を指してるのかピンとこなかったけれど、
解決して改めて見てみると、エラー文はそのまんまの解決策。
【Ruby】多次元配列の定数倍高速化(EDPC J - Sushi)
最初に
EDPC J - Sushiという競プロの問題をRubyで解いてました。
この問題自体は、大学受験数学の難しい方の典型にありそうな問題の延長で、 確率の漸化式を作り式を整理してメモ化再帰の形で動的計画法に乗せると解けます。
詳しい解説は、kyopro_frienedsさんのEDPC解説記事(F~L)を読むといいでしょう。
しかし、Ruby 2.7だと、時間がだいぶギリギリです。 kyopro_friendsさんの解説どおりの解法をとっても、定数倍高速化をしないとTLEになります。 式を整理して定数倍高速化をして、ようやく1900ms台に乗せることができます。 そのせいか、RubyでACされてる方は、kuma_rbさんという方しかいませんでした。
多次元配列の要素数のちょっとした工夫で1950ms前後から1750ms前後と0.2秒ほど速くなったので、定数倍高速化の参考にのせます。
多次元配列の高速化
多次元配列を作るさいに、添字の順番が特に関係ないのであれば、 多次元配列の内側よりも外側の要素数が小さくなるようにして、全体の配列数を減らした方がいいです。
n < mとして、m個の要素の配列をn個作る方が、n個の要素の配列をm個作るよりも、速いです。
生成の比較
require 'benchmark' n = 10**2 m = 10**4 Benchmark.bm(12) do |r| x = r.report("a few arrays"){ a = Array.new(n){ [0] * m } } y = r.report("many arrays "){ b = Array.new(m){ [0] * n } } end # user system total real # a few arrays 0.000397 0.004267 0.004664 ( 0.004749) # many arrays 0.004898 0.004679 0.009577 ( 0.009607)
ローカルで配列の生成を計測した結果で、明らかに差がありました。
配列を作るのは時間のかかる操作で、全体で配列を作る個数が減る方が速いのは当然なのかもしれません。
参照の比較
さらにアクセス時間でも検証しましたが、配列数の少ない多次元配列の方がちょっぴり速そうでした。
require 'benchmark' n = 10**2 m = 10**4 a = Array.new(n){ [0] * m } b = Array.new(m){ [0] * n } Benchmark.bm(12) do |r| r.report("a few arrays"){ n.times{ |i| m.times{ |j| a[i][j] } } } r.report("many arrays "){ n.times{ |i| m.times{ |j| b[j][i] } } } r.report("a few arrays"){ n.times{ |i| ai = a[i]; m.times{ |j| ai[j] } } } r.report("many arrays "){ m.times{ |j| bj = b[j]; n.times{ |i| bj[i] } } } end # user system total real # a few arrays 0.053819 0.000000 0.053819 ( 0.053898) # many arrays 0.089143 0.000000 0.089143 ( 0.089156) # a few arrays 0.045093 0.000000 0.045093 ( 0.045101) # many arrays 0.046487 0.000000 0.046487 ( 0.046492)
その他
ハッシュでは速くならなかった
ハッシュを用いても、今回の問題では速くはなりませんでした。
- 多次元配列の代わりに多次元ハッシュを使うと、TLEしました。
- 多次元ハッシュの代わりに、数値を組み合わせて1つの数値にすることでギリギリAC。
具体的には、
[a][b][c]
の代わりに、[(a * 301 + b) * 301 + c]
という形。 1999msなので本当にギリギリです。
今回の問題でハッシュは有効ではなかったです。 しかし、キーのパターンが少ないケースでは有効と思われるので、一概に決めつけずハッシュが有効なパターンも試してみるといい気がします。
EDPC J - Sushiのための高速化
ブログタイトルから離れて、EDPC J - Sushiの定数倍高足化について。
再帰関数内の分母・分子
再帰関数が呼び出される回数が多いところで、この再帰関数内の定数倍高速化させるかどうかでRuby 2.7で通せる・通せないが変わってくるようです。 分母・分子で同じ値で割っていたらこの部分はコードで計算しないようにしたり、定義して1度しか使わない変数は定義しないようにする必要があったり、細かい部分を頑張る必要があるようです。
もっと速い別の解法
kuma_rbさんという方が1900ms台の解法以外に1350ms前後のもっと速いコードを通していて、根本的にもっと高速化させる方法があるようです。 ちょっと見てみたのですが、異なる解法で難しそうでした。
最後に
このあたりのEDPCの問題は、Ruby 2.7だと厳しいですね。 ちょっとした工夫で、ちょっと速くなることを知れたので良かったです。
インド映画『ダンガル きっと、強くなる』をNetflixで見た
アーミル・カーン主演の映画を見ようと思い、
Netflixにあった『ダンガル きっと、つよくなる』を見ました。
原題は『Dangal』。意味は「レスリング」らしいです。
日本語訳の副題「きっと、つよくなる」は、アーミル・カーンの別映画『きっと、うまくいく』(英題『3 Idiots』) を真似したのでしょう。アーミル・カーンが主演という共通点はありますが、物語の繋がりは特にないです。
話のあらすじは、国の支援がなく金にならず世界を諦めたレスラー国内王者が、娘に夢を託して世界王者に育てあげてていく、というものです。
最初は、果たせたなかった夢を娘に託すというより、娘にやらせるという感じで、アーミル・カーンが昭和の頑固親父みたいだなと思いました。親父の考えが絶対みたいな。特に、長い髪を男の子みたいに短く切られるシーンなど、可愛そうでした。
ただ、物語の中で、"出荷"のように14歳で知らない男と結婚した少女と対比させることで、娘が結婚相手を選べるようになればいいと考えてる父親の考えがクッキリし、娘達も強制から積極的に練習をしたいという考えを持つに至り、そこからは比較的安心して見ることが出来ました。
女の子にレスリングをさせることに反対や嘲笑してた周囲も、結果がでるにつれみんな喜んだり称賛し始めていて、やっぱり新しいことを始める人は始めるとき本当に大変なんだろうな、と感じました。
どこか不器用に感じる父との親子愛を感じさせるスポーツ成長物語、気になった方は見てみてはいかがしょう。
蛇足ですが、ところで、娘は4人いるはずだけど、三女・四女はどうしてるんだろう、と少しだけ気になりました。Wikipedia(英語版)で調べて見ると、三女もレスラーで、映画の公開年2016年にCommonwealth Wrestling Championshipで金メダルを取っているようです。