ようへいの日々精進XP

よかろうもん

2022 年 12 月 05 日 (月)

アクティビティ (今までの走行 (歩行) 距離)

https://pixe.la/v1/users/inokappa/graphs/fitbit-activity

Fitibit Charge2 のアクティビティから走行 (歩行) 距離を Fitbit Web API で取得して Pixela で草生やしている。色が濃くなれば濃くなる程強度が高い (歩行、走行距離が長い) ということで。実装の詳細はこちら

最近、Fitbit Charge2 が壊れてしまったので、データが収集出来ていないことに気づきました。アクティビティの表示はしばらくお休みします...

ジョギング

レアジョブ

12 時からレッスンだった。海外ではリサイクルショップのこと Thrift Shop と呼ぶらしい。

東那珂九日目

待ちに待った昇降デスクが届いた。

夕飯

今宵も鍋。創味シャンタンでスープを作って美味しくいただきました。

Ruby の Enumerable#chunk メソッドを使ってみた

この記事は

YAMAP エンジニア Advent Calendar 2022 の第三日目の記事です。

qiita.com

経緯

チームメンバーに以下のような質問をもらって即答出来ず、夜な夜な試行錯誤していてたら、RubyEnumerable#chunk メソッドに出会った話です。

(質問)

以下のような空行で区切られた数字の羅列があって、区切られた数字毎に合計を計算して、合計の最も大きい数値を表示したいのですが、どのように実装すればエレガントでしょうか?

(数字の羅列)
123
456

789

998
999

本記事で利用する環境は以下の通りです。

root@fbb0a6b38299:/# ruby -v
ruby 3.1.3p185 (2022-11-24 revision 1a6b16756e) [x86_64-linux]

最初の試み

最初に、心のままに書いてみたコードは以下のようなコードでした。

numbers = <<'EOS'
123
456

789

998
999
EOS

datas = numbers.split("\n")

# 数値の合計を入れる配列
_result = []
# 数値を入れる配列
_array = []

datas.each do |d|
  # 配列の要素が empty であれば...
  if d.empty?
    # 数値が入っている配列内の数値を合計して、合計用の配列に突っ込む
    _result << _array.sum
    # 数値を入れる配列を初期化
    _array = []
  else
    # 数値を配列に突っ込む
    _array << d.to_i
  end
end

# 各合計が入っている配列をソートして最後の数値 (最も大きい値) をダンプ
p _result.max

実行してみると、以下のような結果となりました。

root@a68e3293a424:/work# ruby -v
ruby 3.1.3p185 (2022-11-24 revision 1a6b16756e) [x86_64-linux]
root@a68e3293a424:/work# ruby test.rb
789

あれ、なんかおかしい。。。998 + 999 の結果が最大値になりそうですが、789 が最大値として出力されたので意図しない結果です。

空白を区切りとして各要素を足していく戦法は悪く無さそうですが、変数 datas の中身を覗くと以下のような内容となっていて、最後の空白以降の 998 と 998 の足し算が行われていないことが解りました。

["123", "456", "", "789", "", "998", "999"]

次の試み

空白を区切りにするアプローチにこだわって改修してみると、以下のようなコードになりました。

numbers = <<'EOS'
123
456

789

998
999
EOS

datas = numbers.split("\n")

# 最後に空白を追加する
datas.push("")

# 数値の合計を入れる配列
_result = []
# 数値を入れる配列
_array = []

datas.each do |d|
  # 配列の要素が empty であれば...
  if d.empty?
    # 数値が入っている配列内の数値を合計して、合計用の配列に突っ込む
    _result << _array.sum
    # 数値を入れる配列を初期化
    _array = []
  else
    # 数値を配列に突っ込む
    _array << d.to_i
  end
end

# 各合計が入っている配列をソートして最後の数値 (最も大きい値) をダンプ
p _result.max

配列 datas の最後に空白を追加するので、必ず datas の中身は以下のような状態 (配列の最後の要素は "") となります。

["123", "456", "", "789", "", "998", "999", ""]

これで、期待した動作をしてくれそうです。

root@a68e3293a424:/work# ruby test.rb
1997

一旦、これで、チームメンバーに対する面目が立ちそうですが、なんかエレガントさに欠けますね... (汗

そこで Enumerable#chunk を使ってみる

Enumerable#chunk とは

ドキュメントを引用させて頂くと…

> 要素を前から順にブロックで評価し、その結果によって要素をチャンクに分けた(グループ化した)要素を持つ **[Enumerator](https://docs.ruby-lang.org/ja/latest/class/Enumerator.html)** を返します。

とあります。ドキュメントのサンプルコードを見るとなんとなく理解出来ました (なんとなくで恐縮です)

irb(main):001:1* [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5].chunk {|n|
irb(main):002:1*   n.even?
irb(main):003:1* }.each {|even, ary|
irb(main):004:1*   p [even, ary]
irb(main):005:0> }
[false, [3, 1]]
[true, [4]]
[false, [1, 5, 9]]
[true, [2, 6]]
[false, [5, 3, 5]]
=> nil

n.even? の even? は、n が偶数であれば true を返し、奇数であれば false を返す Integer クラスのメソッドで、結果を見ると、n.even? の結果 (true or false) で出力が分割されていることが解ります。

ということは…

chunk メソッドを利用して、数字の羅列を空行 (空白) を区切ってグループ化出来そうです。ということで、以下のように書けそうです。

numbers = <<'EOS'
123
456

789

998
999
EOS

datas = numbers.split("\n")

p datas.chunk {|x| x != "" || nil}.map {|x| x.last }

実行してみると…

root@a68e3293a424:/work# ruby test.rb
[["123", "456"], ["789"], ["998", "999"]]

お、いい感じでチャンクされているように見えます。

あとは各要素を計算するだけ

あとは、チャンクされた各要素の中の数値を合計するコードを書いていきます。

numbers = <<'EOS'
123
456

789

998
999
EOS

datas = numbers.split("\n")

groups = datas.chunk {|x| x != "" || nil}.map {|x| x.last }
p groups

result = []
groups.each do |g|
  result << g.map(&:to_i).sum
end

p result.max

実行してみると…

root@a68e3293a424:/work# ruby test.rb
[["123", "456"], ["789"], ["998", "999"]]
1997

おお、意図した結果となりました!

以上

Ruby の奥深さと楽しさを改めて学ぶことが出来ました。

現場からは以上です。

参考

docs.ruby-lang.org

2022 年 12 月 04 日 (日)

アクティビティ (今までの走行 (歩行) 距離)

https://pixe.la/v1/users/inokappa/graphs/fitbit-activity

Fitibit Charge2 のアクティビティから走行 (歩行) 距離を Fitbit Web API で取得して Pixela で草生やしている。色が濃くなれば濃くなる程強度が高い (歩行、走行距離が長い) ということで。実装の詳細はこちら

最近、Fitbit Charge2 が壊れてしまったので、データが収集出来ていないことに気づきました。アクティビティの表示はしばらくお休みします...

ジョギング

完全休養。

レアジョブ

引き続きお休み。明日の 12 時からレッスン予定。

東那珂八日目

少しずつ生活できるようになった感じ。明日、書斎として利用する予定の洋室にデスクが届く。ガス圧を使って手動で昇降するデスク。設置が楽しみ。そして、ノートパソコン用のアームスタンドも欲しいと思ってはいるけど、実際の導入は様子を見てから。

夕飯

今宵も鍋。明日も鍋だと嬉しいし、妻もお腹が痛くなっていないようで良かった、良かった。

Strava API を使ってアクティビティデータを curl で取得するぞ!

この記事は

YAMAP エンジニア Advent Calendar 2022 の第四日目の記事です。

qiita.com

経緯

ランニング等の日々のトレーニングに Strava を使っている (Garmin と連携させている) ので、運動毎の平均心拍数を時系列に可視化したい気持ちが高まってきました。ということで、まずは、シンプルに curl を使ってアクティビティデータを取得してみたいと思います。

ちなみに、本記事は参考にさせて頂いた記事をほぼそのまま写経させて頂いております。

dev.classmethod.jp

有難うございます!

アクセストークンを確認

下図のように https://www.strava.com/settings/api にてアクセスしてアクセストークンを確認します。既にアプリケーションは登録済みだった (過去に同じことを試みたっぽい) ので、アプリケーションの登録については割愛します。

試しにアクセストークンを利用して自分自身の情報 (Athletes API にアクセスする) を取得してみます。

curl -X GET \
https://www.strava.com/api/v3/athlete \
-H 'Authorization: Bearer YOUR_ACCESS_TOKEN'

正常にレスポンスを返す場合、以下のように出力されました。

{"id":48208003,"username":null,"resource_state":2,"firstname":"Yohei","lastname":"Kawahara",...

OAuth 認証

以下をブラウザのアドレスバーに張り付けます。

https://www.strava.com/oauth/authorize?client_id=${クライアントID}&response_type=code&redirect_uri=http://localhost/exchange_token&approval_prompt=force&scope=activity:read

下図のように出力されます。

「許可する」をクリックすると、以下のような Authorization Code (code) や scope が記録された URL にリダイレクトされます。

Authoirzation Code をコピーして、以下のような URL にアクセスしてアクセストークンを取得します。(クライアントID やクライアントシートは、My API アプリケーションページにて確認すること)

curl -X POST https://www.strava.com/oauth/token \
    -F client_id=${クライアントID} \
    -F client_secret=${クライアントシート} \
    -F code=${Authorization Code} \
    -F grant_type=authorization_code

以下のようなレスポンスを得られました。このレスポンスの access_token を利用してアクティビティデータを取得します。

{"token_type":"Bearer","expires_at":1670134634,"expires_in":17121,"refresh_token":"xxxxxxxxx","access_token":"xxxxxxxx",....

アクティビティデータを取得

curl -X GET \
https://www.strava.com/api/v3/athlete/activities \
-H 'Authorization: Bearer ACCESS_TOKEN'

jq を利用して、以下のような感じで出力させてみました。

$ curl -s -X GET https://www.strava.com/api/v3/athlete/activities \
  -H 'Authorization: Bearer xxxxxxxxxxx' \
  | jq -r '.[]|[.start_date_local,.name,.average_heartrate]|@tsv'
2022-12-03T07:08:51Z    福岡市内トレラン@鴻巣山 145.8
2022-12-02T07:08:48Z    ジョグ@博多駅周辺、山王公園     158.2
2022-11-30T18:36:37Z    ジョグ@山王公園 with 山王公園ランニング倶楽部 (夕練)    145.5
2022-11-30T07:19:12Z    ジョグ@山王公園 (朝練)  158.3
2022-11-28T07:11:31Z    ジョグ@山王公園 (最後はちょっとビルドアップ)    142.5
2022-11-25T07:16:44Z    ジョグ@山王公園とその周辺       165
2022-11-24T07:20:43Z    ジョグ@御笠川   158.8
2022-11-22T07:11:57Z    自宅 de エアロバイク    96
2022-11-21T06:59:22Z    ジョグ@山王公園 142.1
2022-11-19T18:55:18Z    自宅 de エアロバイク (夕練)     110.8
2022-11-19T07:35:15Z    久しぶりの福岡空港ラン  164.8
2022-11-18T19:13:58Z    自宅 de エアロバイク (夕練)     105.8
2022-11-18T07:13:33Z    自宅 de エアロバイク (朝練)     103.7
2022-11-16T07:27:43Z    ジョグ@山王公園 138.5
2022-11-15T19:32:52Z    自宅 de エアロバイク (夕練)     111.7
2022-11-15T06:59:29Z    自宅 de エアロバイク (朝練)     109.9
2022-11-14T17:49:56Z    ジョグ@山王公園 136.8
2022-11-13T08:20:02Z    福岡マラソン 2022 いけるところまで      167.6
2022-11-11T07:35:30Z    自宅 de エアロバイク    119.9
2022-11-10T18:59:12Z    自宅 de エアロバイク    118.5
2022-11-09T18:51:57Z    自宅 de エアロバイク    110.4
2022-11-09T07:02:16Z    ジョグ@山王公園 (最後はちょっとビルドアップ)    144.5
2022-11-08T07:02:56Z    自宅 de エアロバイク    110.6
2022-11-07T07:05:07Z    ジョグ@山王公園 141.2
2022-11-06T07:58:19Z    自宅 de エアロバイク    122.6
2022-11-05T18:39:52Z    自宅 de エアロバイク (夕練)     111.1
2022-11-05T08:20:54Z    ジョグ@山王公園 149.6
2022-11-04T19:15:29Z    自宅 de エアロバイク    108.7
2022-11-03T18:53:56Z    自宅 de エアロバイク (夕練)     118.8
2022-11-03T07:51:56Z    自宅 de エアロバイク (朝練)     114.1

いい感じでアクティビティデータを取得出来ました。

次は

アクティビティデータを可視化してみようと思います。

参考

dev.classmethod.jp

developers.strava.com

2022 年 12 月 03 日 (土)

アクティビティ (今までの走行 (歩行) 距離)

https://pixe.la/v1/users/inokappa/graphs/fitbit-activity

Fitibit Charge2 のアクティビティから走行 (歩行) 距離を Fitbit Web API で取得して Pixela で草生やしている。色が濃くなれば濃くなる程強度が高い (歩行、走行距離が長い) ということで。実装の詳細はこちら

最近、Fitbit Charge2 が壊れてしまったので、データが収集出来ていないことに気づきました。アクティビティの表示はしばらくお休みします...

ジョギング

レアジョブ

引き続きお休み。

東那珂七日目

東那珂に来て一週間が過ぎた。あっと言う間。妻が頑張って引越しの荷物を片付けてくれているので本当にありがたい。

ランチ

香椎のイオンの中で運営していココノヘコーヒーにて。チーズバーガー (ポテト付き) とソフトクリームを頂いた。

www.syouki.jp

夕飯

本当に今宵も鍋で美味しゅうございました。

2022 年 12 月 02 日 (金)

アクティビティ (今までの走行 (歩行) 距離)

https://pixe.la/v1/users/inokappa/graphs/fitbit-activity

Fitibit Charge2 のアクティビティから走行 (歩行) 距離を Fitbit Web API で取得して Pixela で草生やしている。色が濃くなれば濃くなる程強度が高い (歩行、走行距離が長い) ということで。実装の詳細はこちら

最近、Fitbit Charge2 が壊れてしまったので、データが収集出来ていないことに気づきました。アクティビティの表示はしばらくお休みします...

ジョギング

レアジョブ

引き続きお休み。

東那珂六日目

今日もオフィスに出向く必要があったので、寒さに震えながら移動。自宅近辺からオフィスまでどのくらい距離があるのか測ってみたら約 3 キロくらい。

夕飯

今宵も鍋で美味しゅうございました。

2022 年 12 月 01 日 (木)

アクティビティ (今までの走行 (歩行) 距離)

https://pixe.la/v1/users/inokappa/graphs/fitbit-activity

Fitibit Charge2 のアクティビティから走行 (歩行) 距離を Fitbit Web API で取得して Pixela で草生やしている。色が濃くなれば濃くなる程強度が高い (歩行、走行距離が長い) ということで。実装の詳細はこちら

最近、Fitbit Charge2 が壊れてしまったので、データが収集出来ていないことに気づきました。アクティビティの表示はしばらくお休みします...

ジョギング

完全休養。明日は走れるかなー。

レアジョブ

こちらもお休み。

東那珂五日目

オフィスに出向く必要があったので、初めて東那珂から出勤。

夕飯

今宵も鍋で美味しゅうございました。

気になるランニングシューズ

いつもジョギングで利用している HOKA ONE ONE の CLIFTON 8 が 1,000 キロを超えているので、そろそろ代わりの靴が欲しいので物色している。

www.asics.com

ESCALANTE RACER(エスカランテレーサー)メンズaltrafootwear.jp

単純に見た目と、ジョグメインで利用するのでクッション性は確保しつつ厚底過ぎていないところが選択のポイント。

でも、今回の引越しで散財しまくっているので、実際の購入は年明けかな。。。

2022 年 11 月 30 日 (水)

アクティビティ (今までの走行 (歩行) 距離)

https://pixe.la/v1/users/inokappa/graphs/fitbit-activity

Fitibit Charge2 のアクティビティから走行 (歩行) 距離を Fitbit Web API で取得して Pixela で草生やしている。色が濃くなれば濃くなる程強度が高い (歩行、走行距離が長い) ということで。実装の詳細はこちら

最近、Fitbit Charge2 が壊れてしまったので、データが収集出来ていないことに気づきました。アクティビティの表示はしばらくお休みします...

ジョギング

二部練。

レアジョブ

久しぶりに正蔵先生のレッスン。

東那珂四日目

やっとリビングに明かりがついた。

夕飯

今日も鍋で美味しゅうございました。

2022 年 11 月 29 日 (火)

アクティビティ (今までの走行 (歩行) 距離)

https://pixe.la/v1/users/inokappa/graphs/fitbit-activity

Fitibit Charge2 のアクティビティから走行 (歩行) 距離を Fitbit Web API で取得して Pixela で草生やしている。色が濃くなれば濃くなる程強度が高い (歩行、走行距離が長い) ということで。実装の詳細はこちら

最近、Fitbit Charge2 が壊れてしまったので、データが収集出来ていないことに気づきました。アクティビティの表示はしばらくお休みします...

ジョギング

リスタートの次の日には完全休養。

レアジョブ

明日の 9:30 から予約が取れた。

東那珂三日目

妻お気に入りの壁紙に時計を取り付ける為、市販フックの取り付けを試行錯誤していたら、うっかり壁紙が破れてしまって凹んでしまった。そして、エアコンを取り付けた。職人さんの手際の良さもさることながら、エアコン本体や室外機の大きさにびっくり。効き目は良さそうな気がする。

夕飯

久しぶりの鍋で美味しゅうございました。

2022 年 11 月 28 日 (月)

アクティビティ (今までの走行 (歩行) 距離)

https://pixe.la/v1/users/inokappa/graphs/fitbit-activity

Fitibit Charge2 のアクティビティから走行 (歩行) 距離を Fitbit Web API で取得して Pixela で草生やしている。色が濃くなれば濃くなる程強度が高い (歩行、走行距離が長い) ということで。実装の詳細はこちら

最近、Fitbit Charge2 が壊れてしまったので、データが収集出来ていないことに気づきました。アクティビティの表示はしばらくお休みします...

ジョギング

リスタート。

レアジョブ

12 月から頑張ろう。ということで、おやすみ。

東那珂二日目

新しい家からのリモートワーク初日。LAN 設定はバッチリだけど、専用のデスクもないのでダイニングテーブルかリビングで胡座状態。胡座状態で長いミーティングに参加してしまったので腰が痛かった。。。午後から時間休を頂いて、片付けやら買い出し。カップボードとベッドを購入。今回の引越しではテレビ (妻の嫁入り道具で 32 インチ液晶テレビ) 以外の家財道具を一切合財リプレースした。散財しまくったので、色々と頑張っていこうという気持ちになった。

夕飯

買い出しの帰りに引越しお疲れ様会ということで焼き肉を頂いた。美味しゅうございました。