Git Aliasで引数を受け取る
Gitで引数を受け取ることのできるAliasの書き方があるようなので、紹介しておきます。
基本形は以下の通り。
[alias] echo = "!f() { echo ${1}; }; f"
このように~/.gitconfig
記載すると、
$ git echo foo foo
Aliasの先頭に!
を付けるとシェルコマンドとして認識されるので(つけないとpull
やcommit
など、git
コマンドのサブコマンドと認識されます)、つまり上記はシェル関数を定義して即時実行するという仕組みです。 考えてみればシンプルですが、これは物凄く応用範囲が広くて便利です。
たとえば、以下のような感じに使えます。
[alias] ls-repos = "!find . -type d -name .git | xargs dirname" for-all = "!f() { for DIR in $(git ls-repos); do git -C $DIR $@ & done; wait; }; f"
ls-repos
でカレントディレクトリ下のすべてのローカルリポジトリを列挙するエイリアスです。
for-all
は、このls-repos
で列挙した各ローカルリポジトリでgit
コマンドを実行します。
このときサブコマンドを引数として与えているので、任意の操作を行うことができます。
$ ls
repo-1 repo-2 repo-3
$ git for-all pull
Already up to date.
Already up to date.
Already up to date.
みたいな感じ。
個人的には、Go Workspaceで複数リポジトリを使用しているのでこれが便利です。
ちなみに以上はGit AliasのシェルがBashの場合です。Zshだとシンプルにecho = "(){ echo ${1} }"
という感じに書けるとかなんとか。
NuxtJS + Sass(SCSS)でStylelint v14
Stylelint v14から破壊的変更が入り、Sassなどのルールはプラグイン化されました。 それに伴って、すでに導入済みの設定がある場合、いくつかの変更を加える必要があったので記録しておきます。
公式の移行ドキュメントは以下です。
https://stylelint.io/migration-guide/to-14/
結論を先に書くと、追加が必要な依存は以下です。
yarn add -D postcss postcss-scss yarn add -D stylelint-config-standard-scss yarn add -D postcss-html
で、stylelint.config.jsを以下のように修正します(元ファイルはプロジェクト次第なので、あくまで簡略版)。
module.exports = { - extends: ['stylelint-config-standard', 'stylelint-config-prettier'], + extends: ['stylelint-config-standard-scss', 'stylelint-config-prettier'], rules: { 'selector-pseudo-element-no-unknown': [ true, { ignorePseudoElements: ['v-deep'], }, ], }, + overrides: [ + { + files: ['**/*.vue'], + customSyntax: 'postcss-html', + }, + ], }
まずpostcss
ですが、これはSassとかLessを使う場合は基本的に必要となる模様。
SCSSを使いたいのでpostcss-scss
も一緒に追加しています。
stylelint-config-standard-scss
は、今回からプラグイン化されたSCSSのルールです。
インストールしたらstylelint.config.jsのextends
に追加します。
これは公式ドキュメント通り。
最後にpostcss-html
は、<style>
タグに挟まれた部分だけチェックするようにしてくれるものです。
NuxtJS (Vue.js)特有の事情として、*.vueファイル中のスタイルは<style>
タグ内に書くため、これが必要になります。
*.scssファイルなどでは不要なので、stylelint.config.jsのoverrides
で*.vueファイルにのみ適用されるよう設定します。
以上です!
Fedora 35にFlutterをインストール
前提
Android StudioをFlatpak経由でインストール済みの場合を想定しています。 FlatterはSnap経由でインストールするのが簡単そうなのですが、すでにFlatpakを使っており、これ以上パッケージマネージャーを増やしたくないし、このためだけに乗り換えるのもなんだかなあという人の参考になればと思います。
大筋は以下に従います。 docs.flutter.dev
依存関係のインストール
公式によるとClang, CMake, GTK development headers, Ninja build, pkg-configが要るとのことですが、pkg-configはデフォルトで入っているようなのでそれ以外をインストールします。
sudo dnf install ninja-build cmake clang gtk3-devel
Flutterのインストール
ホームにbin/
というディレクトリを掘って、そこにgit clone
します。
どこでもいいのですが、普段から~/bin
に自作スクリプト類を色々と置いてるのでそこに同居させています。
全ユーザーが使うなら/opt/
などがいいと思います。
mkdir ~/bin cd ~/bin git clone https://github.com/flutter/flutter.git
PATHを通します。 .bashrcか.bash_profileに以下を追記してください。
export PATH="$HOME/bin/flutter/bin:$PATH" source ~/.bash_profile
flatter doctorが通るようにする
まずはAndroid Studioを立ち上げ、各種アップデートを完了しておいてください。
Android Studioが大人しくなったら、Flatpak経由で入れた場合のAndroid StudioのパスをFlatterに教えてあげます。
flutter config --android-studio-dir=/var/lib/flatpak/app/com.google.AndroidStudio/current/active/files/extra/android-studio/
つぎに、Android SDKコマンドライン ツールを入れます。
Androidのsdkmanager
コマンドを使えるようにするため、.bashrcか.bash_profileに以下を追記してPATHを通してください。
export PATH="$HOME/Android/Sdk/tools/bin:$PATH" source ~/.bash_profile
今のsdkmanager
はJava8でないと動かないようなので、alternatives
コマンドで切り替えておきます(Java8がインストールされていない場合は入れておいてください)。
以下のコマンドで使用するJavaのバージョンを選択できます。
sudo alternatives --config java
java --version
でJava8に切り替わってることを確認できたら、Android SDKコマンドラインツールのインストールを実行します。
sdkmanager --install "cmdline-tools;latest"
これでflutter doctor
コマンドを実行して、全項目[✓]
になればOKです!
$ flutter doctor Doctor summary (to see all details, run flutter doctor -v): [✓] Flutter (Channel master, 2.6.0-12.0.pre.789, on Fedora Linux 35 (Workstation Edition) 5.14.18-300.fc35.x86_64, locale ja_JP.UTF-8) [✓] Android toolchain - develop for Android devices (Android SDK version 30.0.2) [✓] Chrome - develop for the web [✓] Android Studio [✓] IntelliJ IDEA Community Edition (version 2021.2) [✓] VS Code (version 1.62.3) [✓] Connected device (1 available) • No issues found!
Java 11に戻した上でflutter doctor
しても通ったので、とりあえずこれでOKだと思います。
Fuzzy Containsについて
小ネタです。
かつてあいまい検索といえば、レーベンシュタイン距離などで語句同士の類似度合いを数値化して、域値で絞ったり類似度順に並べるのが普通だったように思います。
ですが、数年くらい前からか、もっと簡単なあいまい検索をよく見かけるようになりました。 AtomやVS Code、GitHubのファイル検索なんかで使われているあれです。
なんて名前なのかな?と思っていたのですが、Fuzzy Containsとか呼ばれているようです。
とても単純なロジックなのでサクッと書けます。 JavaScriptだと以下のような感じ。
function fuzzyContains(query, target) { if (query.length > target.length) return false; for (let i = 0, j = 0, l = query.length; i < l; i++, j++) { j = target.indexOf(query[i], j); if (j === -1) return false; } return true; }
結果は文字が順番通りに含まれているか否かという二値だけですが、場面によってはこれが類似度を使うよりも直感的で使いやすいように感じます。 気に入ったのでいろいろなところで使っていきたいと思います。
ホーナー法について
たいしたことないネタでもちょいちょい記事を書いてみることにします。今日はホーナー法について。
多項式を計算する際、乗法の回数を削減することができます。上記リンク先によると、19世紀からある方法のようです。
やり方はとてもシンプルです。以下のような多項式があるとします。
これを、次のように変形するだけです。
JavaScriptで実装すると、以下のような感じになります。
var horner = (coeffs = [], x) => coeffs.reduce((a, b) => a * x + b, 0);
もしくは、簡潔さより高速さということであれば、以下のような感じでしょうか。
var horner = (coeffs = [], x) => { var r = coeffs[0]; for (let i = 1, l = coeffs.length; i < l; i++) r = r * x + coeffs[i]; return r; }
第一引数には、]の順に係数の配列を渡します。
実際のところ、べき乗の計算は効率的なアルゴリズムが知られているため、素直に展開形を実装するのに比べて、ホーナー法でそこまでの高速化は期待できません。 ただ、特に小数がある場合、計算精度の向上を望めます。
また、FMA (Fused Multiply-Add) をサポートしている環境では、更なる精度向上が期待できそうです。
例えばJuliaはfma()
関数を呼び出すことで、CPUが対応していればFMAを使うことができます。
function horner(coeffs, x) r = coeffs[1] for i in 1:length(coeffs) r = fma(r, x, coeffs[i]) end r end
FMAについては、以下のブログ記事が参考になりました。
ちなみに、JuliaについてはBase.Math
中に@horner(x, p...)
というマクロが予め定義されているようです。
以下のようにして呼び出すことができます。
julia> using Base.Math: @horner julia> a0, a1, a2 = 0.123, 0.234, 0.345 julia> x = 0.999 julia> @horner x a0 a1 a2 0.701076345
とても簡単に使えるアルゴリズムなので、ぜひ活用したいです。
以下の本を参考に書きました。
[改訂新版]C言語による標準アルゴリズム事典 (Software Technology)
- 作者: 奥村晴彦
- 出版社/メーカー: 技術評論社
- 発売日: 2018/04/19
- メディア: 単行本(ソフトカバー)
- この商品を含むブログ (1件) を見る
出てきやすいパターン
みんなどうせ暇だろうから確率の問題ね。
— はりてゃ (@Woofer30) 2018年5月8日
Q. 均等なコインを連続して投げ、表が出たら1、裏が出たら0を順次書いていく。パターン「10」と「11」とでは、平均するとどちらが少ない投げる回数で出る?
A. 「10」は平均4回、「11」は平均6回なので、「10」の方が少ない。 https://t.co/qvFDOurY0T
— はりてゃ (@Woofer30) 2018年5月9日
この問題、なんとなく「10」でも「11」でも平均でみたら同じになりそうな気がしてしまいます。
せっかくなのでJavaScriptで計算実験してみました。
// コインを投げる function tossCoin() { return Math.round(Math.random(), 1); } // パターンが出るまでコインを投げる function tossUntil(pattern) { let r = ''; do { r += tossCoin(); } while (r.lastIndexOf(pattern) === -1); return r; } // n回試行して結果を配列に詰める function genData(n, pattern) { const array = []; for (let i = 0; i < n; i++) { array.push(tossUntil(pattern).length) } return array; } // 平均を計算する function average(array) { return array.reduce((x, y) => x + y, 0) / array.length; } // テストを実行する function runTest() { const n = 10000; const E10 = average(genData(n, '10')); const E11 = average(genData(n, '11')); alert(`E(N10) = ${E10}\nE(N11) = ${E11}`); } runTest();
結果は次のようになりました。
E(N10) = 4.146 E(N11) = 6.039
なんとなく「10」は4回、「11」は6回に収束していきそうな感じがします。
以下のリンクを押すとお使いのブラウザから試せます。
問題の出典は以下の本です。解法が気になる場合は読んでみてください。
- 作者:G.ブロム
- 発売日: 2012/07/17
- メディア: 単行本