コード日進月歩

しんくうの技術的な小話、メモ、つれづれ、など

Railsでインスタンス変数に代入することをメモ化と呼ぶのは趣の違う話なのでざっくりまとめる

表題通り違和感をまとめる。

前提としてメモ化とは

Wikipedia曰く以下の通り

メモ化(英: Memoization)とは、プログラムの高速化のための最適化技法の一種であり、サブルーチン呼び出しの結果を後で再利用するために保持し、そのサブルーチン(関数)の呼び出し毎の再計算を防ぐ手法である。 (中略) メモ化された関数は、以前の呼び出しの際の結果をそのときの引数と共に記憶しておき、後で同じ引数で呼び出されたとき、計算せずにその格納されている結果を返す。メモ化可能な関数は参照透過性を備えたものに限られる。すなわち、メモ化されたことで副作用が生じない場合に限られる。 - メモ化 - Wikipedia

ということでメソッドや関数において、同一の引数の場合は再計算せず保存した値を出すことで速度を稼ぐ手法。

Rubyの簡単な例

フィボナッチ数列の例が多いのでそれを題材とする、まずはメモ化しない例

class CalcFibonacci
  # フィボナッチ数列は1個前と2個前の合計値
  def fibonacci(n)
    # 0と1は前がないので
    if n <= 1
      n
    else
      fibonacci(n-1) + fibonacci(n-2)
    end
  end
end

これを計算結果をmemorizeすると以下

class CalcFibonacci
  def initialize
    @cache = {}
  end

  def fibonacci_with_memorize(n)
    # すでに計算済みであれば返却
    return @cache[n] if @cache.has_key?(n)
    if n <= 1
      result = n
    else
      result = fibonacci_with_memorize(n-1) + fibonacci_with_memorize(n-2)
    end

    @cache[n] ||= result
    result

  end
end

メモ化することで再計算がされなくて済む

メモ化のようでメモ化ではない例

Railsにおいて以下の動作がメモ化の例として取り上げられることがある。

def user
  @user ||= User.find(params[:id])
end

一見メモ化のように見えるが、メモ化は以下の通りなので趣が違う。

メモ化された関数は、以前の呼び出しの際の結果をそのときの引数と共に記憶しておき、後で同じ引数で呼び出されたとき、計算せずにその格納されている結果を返す。

これはparamsの値を使っている時点でクラスの状態に左右されるため、引数の値を使うという部分でことなる。そのため上記のようなRailsの例はメモ化というよりはDB読み込みのキャッシュとなる。

参考リンク

TC39とはなにかをざっくりまとめる

mozaic.fmを聞いていると登場するが、どのような組織か知らないのでざっくり調べる

出典

TC39 - Ecma International

上記の内容曰く「ECMAScriptを標準化するための専門委員会」。なおECMAは様々な技術委員会を持ち、TC39はそのうちのひとつ。

TC39がやっていること

出典サイトには以下のようなことを取り組むチームと書いてある

  • ECMAScriptの標準化維持とアップデート.
  • ECMAScriptの機能拡張ライブラリのメンテナンス.
  • 標準化された仕様を維持するためのテストスイートの提供.
  • 標準化した仕様のISO/IEC JTC 1への提供.
  • 追加の技術検討.

参考リンク

プログラミングにおけるバニラという意味をざっくり調べる

雰囲気で使っていたのでTips的な話。

出典

バニラ (ソフトウェア) - Wikipedia)

プログラミングとしてのバニラ

英和辞書で引くと形容詞としては「質素で余分なものや装飾品のない」という内容があり、プログラミングでも似た概念で利用され、「普通」の状態のままのものを表すものとして使われる。

古いとされる利用例

初出に関しては情報がないが、インターネット上に存在する例だと2002年につくられたとされるHTMLの変換ソフトウェアのマニュアル内でなにもない設定ファイルのことを BookMaster's "vanilla" DVCF macros と記載されており、2002年ごろから使われていたことがわかる。またこの使用例ではvanillaの対義語としてmoca(モカ)という表現が使われている

関連リンク

JSで時刻操作をする場合、moment.jsは公式にプロジェクトの終了がアナウンスされたので別のものを検討する

表題通り。

元ネタ

Moment.js | Docs より

We now generally consider Moment to be a legacy project in maintenance mode. It is not dead, but it is indeed done. - 現在では、Momentはメンテナンスモードに入ったレガシープロジェクトであると考えています。死んだわけではありませんが、確かに終わったのです。

上記のページに加えてに説明があり

  • moment.jsを使わなければ行けないケースの紹介
  • 代替ライブラリ、実装の紹介

などがあり、案内としてはかなり丁寧な説明となっている。

紹介されている代替案

  • Luxon - moment.jsの進化として紹介されている
  • Day.js - IE対応などを鑑みた場合に勧められているライブラリ
  • date-fns - 作りのシンプルさを売りにしているライブラリ。Day.jsと比較して語られることが多い。
  • js-joda - Javaの時間操作ライブラリJoda-Time を模倣したライブラリ(とのこと)
  • ライブラリを使わない - 簡単な操作ならピュア実装でもいける

参考/関連リンク

BigQueryで単一のクエリ内で値を定義して定数のように使い回す

いろんなテーブルをまたいで利用するときに似たようなクエリをつくるのでその時のための機能

前提条件

  • STANDARD SQLです(記載タイミングでレガシーのほうを使っているほうが稀かなと思いますが念の為)

やり方

定数定義のような機構はこの記事を書いている時点では存在しないので値だけを返す一時的なユーザー定義関数を作る。

ユーザー定義関数は CREATE FUNCTION を利用する、今回利用する範囲での最低限の文法としては以下

# 関数定義
CREATE TEMPORARY FUNCTION {{一時定義の関数名}}() AS ( {{返却したい処理}} )  

もっとオプションがあるが、そちらに関しては参考リンクのドキュメントをご覧いただければと思います。

実行時のYYYYMMDDの値をとってクエリに活用する。

以下の例は dateが実行日と一致するものかつ、last_update_date内に実行日のYYYYMMDDが含まれているものを探すクエリ

CREATE TEMPORARY FUNCTION QUERY_EXECUTE_NOW_DATE()
AS(
  FORMAT_TIMESTAMP("%Y%m%d" ,CURRENT_TIMESTAMP)
);

SELECT * FROM `example-project.example-dataset.example_table_20100801`
WHERE data = QUERY_EXECUTE_NOW_DATE()
AND last_update_date = QUERY_EXECUTE_NOW_DATE()

参考リンク

RubyのURIクラスを使ってハッシュをクエリ文字列にする、URLからクエリ文字列をハッシュ化する

あんまり直球な情報がないのでメモがてら

環境

$ ruby -v
ruby 2.6.3p62 (2019-04-16 revision 67580) [universal.x86_64-darwin19]

やり方

URLからハッシュ化

target_url_with_query = "https://example.com?equal_string=ZXhhbXBsZXNleG1hcGxlcw%3D%3D&example=huga"
query_hash = URI.decode_www_form(URI.parse(target_url_with_query).query).to_h

ハッシュからクエリストリング生成

url = "https://example.com"
query_hash = {"equal_string"=>"ZXhhbXBsZXNleG1hcGxlcw==", "example"=>"huga"}
target_url_with_hash = "#{url}?#{URI.encode_www_form(query_hash)}"

余談

decode_www_form はデコード時にURLエスケープがかかっていると自動的に戻してくれる。あまりないユースケースだがそのままパラメータ文字列をkeyとvalueに分割したい場合は以下のように愚直にバラすしかない

target_url_with_query = "https://example.com?equal_string=ZXhhbXBsZXNleG1hcGxlcw%3D%3D&example=huga&hiragana=44Gy44KJ44GM44Gq5paH5a2X5YiXCC4%3D"
query_hash = target_url_with_query.split("/").last.split("?").last.split("&").each_with_object({}) do |key_value_set,result|result[key_value_set.split("=")[0]] = key_value_set.slice(key_value_set.split("=")[0].size+1..-1) end
# => {"equal_string"=>"ZXhhbXBsZXNleG1hcGxlcw%3D%3D", "example"=>"huga", "hiragana"=>"44Gy44KJ44GM44Gq5paH5a2X5YiXCC4%3D"}

関連リンク

BigQueryでJOIN時に各々のテーブルに_TABLE_SUFFIXを適用する方法

イマイチすぐに出てこないのでメモがてら

前提条件

  • STANDARD SQLです(記載タイミングでレガシーのほうを使っているほうが稀かなと思いますが念の為)

そもそも _TABLE_SUFFIX とは

こちらに関しては別記事で書いたのでそちらを参考のこと

書き方

カラム名に関してテーブル名を指定するのと同じ書き方でできる。以下は別々のテーブルに対してTABLE_SUFFIXを当てている書き方

SELECT hoge FROM `example-project.example-dataset.example_table_2010*` AS table_a
LEFT JOIN `example-project.example-dataset.join_table_2010*` AS table_b
WHERE table_a._TABLE_SUFFIX = "0801"
AND table_b._TABLE_SUFFIX = "0801"

GoogleAnalyticsのBigQueryExportサンプルをJOINして表現しています(いい例がなかったので同じテーブルをJOINしています…)

SELECT original_table.visitStartTime , original_table.fullVisitorID 
FROM `bigquery-public-data.google_analytics_sample.ga_sessions_2016*` AS original_table
LEFT JOIN `bigquery-public-data.google_analytics_sample.ga_sessions_2016*` AS join_table ON original_table.fullVisitorID = join_table.fullVisitorID
WHERE original_table.fullVisitorId = "0001363886612345162"
AND original_table._TABLE_SUFFIX = "0803" 
AND join_table._TABLE_SUFFIX BETWEEN "0801" AND "0831"

参考リンク