将来的に Rust のリンカーが変わるかもってさ
RSS で以下の記事が流れてきました。
最近リンク時間が気になるので読みました。 勝手訳なので怒られたら消すかもです。 意訳誤訳超訳あると思うので、畳んである原文を見たり、Twitter (現 Twitter) でツッコミをくださったりしてください。
訳は以下です。
Linux nightly で rust-lld を使うことでリンク時間が早くなります。
TL;DR: rustc は x86_64-unknown-linux-gnu の nightly で、リンク時間を劇的に減らすために rust-lld を使うようになります。
原文
Faster linking times on nightly on Linux using rust-lld
TL;DR: rustc will use rust-lld by default on x86_64-unknown-linux-gnu on nightly to significantly reduce linking times.
いくつかの前提
リンク時間はしばしば、コンパイル時間の中の大部分になります。 rustc が実行可能バイナリーや共有ライブラリーを作成する必要があるとき、システムにインストールされている標準のリンカーを普通は呼びます。 (これはコマンドラインからかソースコードをコンパイルするときのターゲットごとにで変更できます。(カッコ内微妙かも。))
原文
Some context
Linking time is often a big part of compilation time. When rustc needs to build a binary or a shared library, it will usually call the default linker installed on the system to do that (this can be changed on the command-line or by the target for which the code is compiled).
リンカーは安定性や後方互換性などに関係する重要な仕事をします。 これらや他の理由のため、著名な OS では、コンピューターがシングルコアだったときに設計された古いプログラムを普通使います。 なので、最近のマシンではリンクは遅い傾向があります。 例えば、ripgrep 13 を Linux で debug ビルドするとき、リンカーの時間がだいたい半分を占めます。
原文
The linkers do an important job, with concerns about stability, backwards-compatibility and so on. For these and other reasons, on the most popular operating systems they usually are older programs, designed when computers only had a single core. So, they usually tend to be slow on a modern machine. For example, when building ripgrep 13 in debug mode on Linux, roughly half of the time is actually spent in the linker.
異なるリンカーもあって、リンク時間を改善するいつものアイデアは、それらの中の新しくて早いリンカーを使うことになります。
LLVM の lld や Rui Ueyama の mold などです。
原文
There are different linkers, however, and the usual advice to improve linking times is to use one of these newer and faster linkers, like LLVM's lld or Rui Ueyama's mold.
いくつかの Rust ターゲットの、wasm や aarch64 ターゲットなどは最初から lld を使います。
rustup を使うとき、rustc はこの目的のために lld を同梱します。
CI でコンパイラーとして LLVM 使うためにビルドするとき、リンカー (lld) も一緒にビルドされてパッケージングされます。
これは rust-lld と呼ばれて、すでにマシンにインストールされている lld との衝突を回避します。
原文
Some of Rust's wasm and aarch64 targets already use lld by default. When using rustup, rustc ships with a version of lld for this purpose. When CI builds LLVM to use in the compiler, it also builds the linker and packages it. It's referred to as rust-lld to avoid colliding with any lld already installed on the user's machine.
リンク時間の改善がかなりのものであるため、人気のあるターゲットでデフォルトで使うようにすることは良い選択肢でしょう。
長い間議論されていました。
例として、#39915 と #71515 の issue や、nightly フラグで rust-lld を rustc は提供していました。
原文
Since improvements to linking times are substantial, it would be a good default to use in the most popular targets. This has been discussed for a long time, for example in issues #39915 and #71515, and rustc already offers nightly flags to use rust-lld.
いま、CI や crater、ベンチマークインフラで我々の内部テストでできることは全部やったと思います。
テストの領域を広げて、現実世界 (もっと良い訳ありそう) のフィードバックやユースケースを集めます。
だから、rust-lld を x86_64-unknown-linux-gnu の nightly ビルドのデフォルトリンカーとして有効にします。
(crater あんまり良くわかってないけどたぶんこれだろうと思ってリンク貼ったけど合ってるのかなあ。)
原文
By now, we believe we've done all the internal testing that we could, on CI, crater, and our benchmarking infrastructure. We would now like to expand testing and gather real-world feedback and use-cases. Therefore, we will enable rust-lld to be the linker used by default on x86_64-unknown-linux-gnu for nightly builds.
何が嬉しいのか
これによって、将来的にもっとリンカーの機能をコンパイラーが使えるようになったりします。 即時のメリットとしてリンク時間がとても改善します。
原文
Benefits
While this also enables the compiler to use more linker features in the future, the most immediate benefit is much improved linking times.
以下はより詳細な ripgrep の例です。 リンク速度は 7 倍になって、コンパイル時間の全体は 40% 削減されます。
原文
Here are more details from the ripgrep example mentioned above: linking is reduced 7x, resulting in a 40% reduction in end-to-end compilation times.
ほとんどの実行可能バイナリーで改善があり、特に影響があるのは、大きい実行可能バイナリーやデバッグ情報を含むものです。 これらのボトルネックは普通リンカーにあります。
(原文の but ってなんだろう?訳あんまり合ってないかも。)
原文
Most binaries should see some improvements here, but it's especially significant with e.g. bigger binaries, or when involving debuginfo. These usually see bottlenecks in the linker.
原文
Here's a link to the complete results from our benchmarks.
テストが上手く行ったら、x86_64-unknown-linux-gnu ユーザーがデフォルトで早いリンカーを使うよう安定化して、他のターゲットもそうするでしょう。
原文
If testing goes well, we can then stabilize using this faster linker by default for x86_64-unknown-linux-gnu users, before maybe looking at other targets.
あり得る欠点
我々の初期テストより、実際には問題が発生するとは本当には思っていません。
非常に多くの場合でそのまま置き換えられますが、しかし lld は GNU ld のバグ互換性まではありません。
原文
Possible drawbacks
From our prior testing, we don't really expect issues to happen in practice. It is a drop-in replacement for the vast majority of cases, but lld is not bug-for-bug compatible with GNU ld.
もし問題が発生したら、どんな場合でも、rust-lld を使うことを無効化できます。
-Z linker-features=-lld フラグを使うと、システムの標準のリンカーを使うように戻せます。
原文
In any case, using rust-lld can be disabled if any problem occurs: use the -Z linker-features=-lld flag to revert to using the system's default linker.
これらの違いに依存しているいくつかのクレートは、追加のリンカーへの引数を必要とします。 (somehow がわからん。)
例えば、crater の 20 個未満のクレートは、encapsulation symbols についてのデフォルトの違いのためにリンクの実行に失敗します。
これらはレガシーな GNU ld の挙動に合わせるため -Clink-arg=-Wl,-z,nostart-stop-gc が必要です。
原文
Some crates somehow relying on these differences could need additional link args. For example, we saw <20 crates in the crater run failing to link because of a different default about encapsulation symbols: these could require -Clink-arg=-Wl,-z,nostart-stop-gc to match the legacy GNU ld behavior.
性能向上を大きく獲得するのは並列化から来ているため、リソースに制限のある環境では望まぬ結果になる可能性があります。
原文
Some of the big gains in performance come from parallelism, which could be undesirable in resource-constrained environments.
まとめ
rustc は rust-lld を x86_64-unknown-linux-gnu の nightly で、リンク時間の大きな改善のため、明日の rustup nightly (nightly-2024-05-18) から使うようになります。
もし問題を見かけたら、GitHub で issue を開いて 我々に教えて下さい。
もし問題が発生したら -Z linker-features=-lld フラグでデフォルトリンカーに戻せます。
いつもの RUSTFLAGS 環境変数に追加するか、プロジェクトの .cargo/config.toml 設定ファイルに以下のように書くかのいずれかです。
[target.x86_64-unknown-linux-gnu] rustflags = ["-Zlinker-features=-lld"]
原文
Summary
rustc will use rust-lld on x86_64-unknown-linux-gnu nightlies, for much improved linking times, starting in tomorrow's rustup nightly (nightly-2024-05-18). Let us know if you encounter problems, by opening an issue on GitHub.
If that happens, you can revert to the default linker with the -Z linker-features=-lld flag. Either by adding it to the usual RUSTFLAGS environment variable, or to a project's .cargo/config.toml configuration file, like so:
[target.x86_64-unknown-linux-gnu] rustflags = ["-Zlinker-features=-lld"]
The Nominomicon の非公式翻訳を作った (Rust パーサー)
The Nominomicon の非公式翻訳を作った。
GitLab Pages でホスティングしてます。 https://nogiro.gitlab.io/nominomicon-unofficial-japanese-translation/
意訳・超訳が多いと思うので、指摘などあれば GitLab に issue を作ってもらえるとありがたいです。 8 章は内容はあったけど SUMMARY からリンクされておらずビルドされないので、翻訳せずそのままにしています。
New GitLab Issue: https://gitlab.com/nogiro/nominomicon-unofficial-japanese-translation/-/issues/new
英語へたくそなので中々大変だったけど、翻訳作業そのものが nom の理解の助けになって良かった。
npm の dotenv と cargo-make の --env-file オプションで、パースのされ方が異なったので調査
npm の dotenv パッケージと cargo-make の --env-file オプションで、パース方法に違いがあったので調べた結果をまとめました。
調査に利用したソースは https://gitlab.com/nogiro/dotenv-inspection に配置しています。
違いがあったのは ' (シングルクォート) と # (シャープ) まわりです。
この記事で比較するのは以下の 2 個です。
上記リポジトリーを clone すると、以下の .env ファイルを用意してあります。
DOTENV_INSPECTION_NOT_QUOTED=foo#bar DOTENV_INSPECTION_SINGLE_QUOTED='foo#bar' DOTENV_INSPECTION_DOUBLE_QUOTED="foo#bar"
npm install・cargo install cargo-make の後で、npm run env と cargo make --env-file .env env を実行するとそれぞれの違いが確認できます。
npm run --silent dev
DOTENV_INSPECTION_NOT_QUOTED=foo DOTENV_INSPECTION_SINGLE_QUOTED=foo#bar DOTENV_INSPECTION_DOUBLE_QUOTED=foo#bar
クォートされていない場合は、# 以降がコメントとして削除されていることが確認できます。
cargo make --quiet --env-file .env env
DOTENV_INSPECTION_SINGLE_QUOTED='foo#bar' DOTENV_INSPECTION_NOT_QUOTED=foo#bar DOTENV_INSPECTION_DOUBLE_QUOTED=foo#bar
シングルクォートでクォーテーションした場合に、シングルクォートが残っていることが確認できます。(また、逆順にソートされるようです。)
まとめ
npm の dotenv と cargo-make を同時に利用するプロジェクトでは、# を含む値はダブルクォートで囲むと良いようです。
(リポジトリーでは envmnt (cargo-make が利用してる crate) と Rust の dotenv crate、python-dotenv も比較しています。)
Dwarf Fortress プレイ中にググった英単語 (自分用メモ、随時追記)
- throne: 玉座
- pedestal: 台
- brook: 小川
- mussel: ムール貝
- drowsy: 眠い
- jade: ヒスイ
- gneiss: 花崗岩
- confinement: 監禁
- 小動物を捕まえたら (?) 出た
- shear: 剪定
- 羊とかの毛刈りだろう
- grackle: ムクドリ
- galena: 方鉛鉱
- eradicate (eradicating): 絶滅させる
- heirloom: 家宝
- worship: 崇拝
- pewter: ピューター
- なんの訳にもなっていない……
スズを主成分とする古くからある低融点合金である。成分の一例はスズ93%、アンチモン7%
- なんの訳にもなっていない……
- pig iron: 銑鉄
- electrum: 「金と銀の合金」らしい
electrumとは・意味・使い方・読み方・例文 - 英ナビ!辞書 英和辞典- 仮想通貨ではない
- hematite: 赤鉄鉱
- quartzite: 珪岩
- calf: 子牛
- cow: 雌牛
- bull: 雄牛
- tallow: 獣脂
- petition: 請願、嘆願、申請、請願書
- persimmon: 柿
- sedimentary: 沈殿物の、沈殿作用による、沈積によって生じた (Wiki)
- cartilage: 軟骨
- bituminous coal: 瀝青炭
- lignite: 褐炭
- limonite: 褐鉄鉱
- billon: ビロン、貨幣用合金
- どういうこと……?
ビロン(billon)は、合金の一種で、貴金属(主に銀だが、金の場合もある)と主成分となる金属(銅など)を混ぜたものである。硬貨、メダル、代用貨幣などの製造に用いられる。
- どういうこと……?
- quicklime: 生石灰
- pearlash: 真珠灰 (不純な炭酸カリウム)
- gypsum: 石膏
- tallow: ヘット、牛脂
- sarcophagus: サルコファガス
- stew: シチュー
- orthoclase: 正長石
- interrogate: 尋問する
- convict: 有罪判決を下す
- witness: 目撃者
- expell: 追放する
nginx リバースプロキシの後ろの plantuml を VM 管理から docker-compose に変更する
目的
仮想マシンで提供していた plantuml-server を Docker コンテナーに変更します。
plantuml-server は↓を tomcat で稼働させていました。 github.com
前提
nginx を docker-compose でリバースプロキシとして利用している
https://example.com/plantuml/ で plantuml サーバーを提供しています。
/plantuml にアクセスすると nginx が仮想マシン (192.0.2.170) に転送するようにしています。1
location /plantuml/ {
# etc...
proxy_pass http://192.0.2.170:8080;
}
修正内容
サブディレクトリー対応するよう plantuml/Dockerfile を作成
Docker Hub に plantuml-server があります。
が、サブディレクトリー (/plantuml) に対応していないため、そのままでは利用できません。
https://example.com にアクセスすると plantuml server が見られる状態を https://example.com/plantuml に変えたいです。
Jetty は war の名前を変えると対応できるので、以下の Dockerfile を書きます。
FROM plantuml/plantuml-server:jetty ARG BASE_URL=plantuml RUN mv /var/lib/jetty/webapps/ROOT.war /var/lib/jetty/webapps/$BASE_URL.war
(ROOT.war は特殊なファイル名のようです。https://example.com/ROOT ではなく https://example.com へのアクセスで公開されるアプリケーションになります。)
docker-compose.yml への追加
docker-compose.yml からの相対パスが plantuml/Dockerfile の位置に、先程の Dockerfile を配置します。
docker-compose.yml に plantuml サービスを追加します。
plantuml: build: ./plantuml/ restart: always
また、nginx サービスに plantuml へのネットワーク接続を追加します。
nginx:
image: nginx:1.14.2-alpine
volumes:
- ./files/nginx/etc/letsencrypt:/etc/letsencrypt
- ./nginx/conf.d:/etc/nginx/conf.d
ports:
- 192.0.2.146:443:443
restart: always
+ links:
+ - plantuml
docker-compose を再起動します。
docker-compose build && (docker-compose down; docker-compose up -d)
nginx 設定の修正・適用
nginx/conf.d/default.conf を修正します。
- proxy_pass http://192.0.2.170:8080; + proxy_pass http://plantuml:8080;
nginx プロセスの設定を更新します。
docker-compose exec nginx nginx -s reload
疑問点
plantuml/plantuml-server:jetty の Dockerfile では ARG でサブディレクトリーが指定されています。
docker-compose で args を指定できるのは build (image ではなく) のときなので使いませんでした。
docker-compose.yml で完結せずに Dockerfile を作らないといけないのは収まりが悪いですが、実はどうにかできるのでしょうか。
-
192.0.2.0/24は例示用 IPv4 アドレス https://tools.ietf.org/html/rfc5737↩
apt-cacher-ng を回避して Docker をインストールする
要約
apt-cacher-ng 環境下では download.docker.com へ接続できず Docker をインストールできないので
echo 'Acquire::HTTP::Proxy::download.docker.com "DIRECT";' > /etc/apt/apt.conf.d/70docker
して直接ダウンロードするようにしましょう。
なぜ書くか
毎回毎回忘れていて Twitter で 「docker from:nogiro_iota」を検索して↓を探すハメになるので自分用メモとして書いています。
apt-cacher-ng 噛ませてると docker の apt リポジトリが 403 出る、という謎の現象に遭遇した
— のぎろ (@nogiro_iota) 2018年12月16日
apt の設定に 「Acquire::HTTP::Proxy::https://t.co/UQZSFhEv2s "DIRECT";」 を追加して、docker のリポジトリだけキャッシュ噛ませないようにすると良いみたい https://t.co/IHePah6unK
本題
パッケージマネージャー apt には、パッケージのダウンロードをプロキシしてキャッシュしてくれる仕組みの apt-cacher-ng があります。
apt-cacher-ng 環境下で Docker をインストールすると download.docker.com へ接続できずに失敗します。
以下の公式のインストール手順にしたがって進めていると
docs.docker.com
INSTALL DOCKER ENGINE - COMMUNITY セクションの apt update が失敗します。(add-apt-repository の次)
$ sudo apt update Err:1 https://download.docker.com/linux/debian buster InRelease Reading from proxy failed - read (115: Operation now in progress) [IP: 192.0.2.0 3142] Hit:2 http://deb.debian.org/debian buster InRelease Hit:3 http://deb.debian.org/debian buster-updates InRelease Hit:4 http://security.debian.org/debian-security buster/updates InRelease Reading package lists... Done Building dependency tree Reading state information... Done All packages are up to date. W: Failed to fetch https://download.docker.com/linux/debian/dists/buster/InRelease Reading from proxy failed - read (115: Operation now in progress) [IP: 192.0.2.0 3142] W: Some index files failed to download. They have been ignored, or old ones used instead.
当時調べたところ、apt の設定で apt-cacher-ng を回避する方法が出てきました。
github.com
ので設定します。(Twitter からコピーすると http:// がついてめんどかったのですよね。)
$ echo 'Acquire::HTTP::Proxy::download.docker.com "DIRECT";' > /etc/apt/apt.conf.d/70docker
apt update が成功します。
$ sudo apt update Hit:1 http://deb.debian.org/debian buster InRelease Get:2 http://deb.debian.org/debian buster-updates InRelease [49.3 kB] Get:3 https://download.docker.com/linux/debian buster InRelease [44.4 kB] Get:4 https://download.docker.com/linux/debian buster/stable amd64 Packages [10.3 kB] Hit:5 http://security.debian.org/debian-security buster/updates InRelease Fetched 104 kB in 1s (79.5 kB/s) Reading package lists... Done Building dependency tree Reading state information... Done All packages are up to date
後書き
この記事を書いているときに調べたところ、HTTPS だと失敗するようです。
wiki.debian.org
apt-cacher-ng 側の設定で回避できそうなのでストレスフリーになりそうです。
第41回シェル芸勉強会 - Python ワンライナー版解答
第 41 回シェル芸勉強会の問題の Python ワンライナーでの解答です。
真面目なほうは 第41回シェル芸勉強会に参加しました。 - nogiro_iotaのメモ を参照してください。
けっこう改訂しています。(解説も追加する予定です。しました。)
改訂履歴を最下段に載せています。
まとめ
python3 -c 'import sys; [print(x[:-1]) for x in sorted(sys.stdin, key=lambda x:hoge)]' で hoge をいじれば標準入力を好き勝手ソートできる。
全体に共通する解説
第 41 回シェル芸勉強会はソート回とのことでした。
Python でのソートは sort()・sorted() の 2 種類です。この記事中の回答ではすべてsorted()を使用しています。sorted()は引数として iterable なオブジェクト (sys.stdin やリスト) を受け取って、ソート済みのリストを返すためワンライナーで扱い易いためです。(sort() はリスト型クラスのメソッドで、呼ぶとリスト内部をソートして返り値は None になります。)
printf デバッグ
Python は短絡評価してくれて print() は None を返すので、値を見たい部分で print(hoge) or hoge すると printf デバッグできます。
以下は A4-2 を例にしています。
$ python3 -c '[print(x.strip()) for x in sorted(open("ShellGeiData/vol.41/sjis", "r", encoding="cp932"), key=lambda x:print(int(x.split()[0])) or int(x.split()[0]))]'
123
31
20
2242
20 ほじぱんふんじこみ
31 こきたてひーひー
123 ずんごるももう
2242 うえってきたかるとらまん
問題と Python ワンライナー版解答
sorted() の key でソート基準を決める関数を渡せるのでけっこう簡単でした。
Q1
次のファイルについて、2列目をキーにしてエクセルの横列の記号(A, B, ..., Z, AA, AB, ...のやつ)順に並べ替えてください。
$ cat excel 114514 B 1192296 AA 593195 CEZ 4120 TZ 999 QQQ
A1
$ cat ShellGeiData/vol.41/excel | python3 -c 'import sys; [print(x[:-1]) for x in sorted(sys.stdin, key=lambda x:("%%%"+x.split()[1])[-4:])]'
114514 B
593195 AA
4120 TZ
1192296 CEZ
999 QQQ解説
解き方自体は前記事と同じです。列番号は
x.split()[1] で得られるので、前部分に"%%%"をつけて後ろ 4 文字 ([-4:]) を返すようにします。
Q2
次のファイルのレコードを干支順にソートしてください。
$ cat eto_yomi 申 さる 子 ね 寅 とら 卯 う 巳 み 辰 たつ 丑 うし 酉 とり 戌 いぬ 亥 い 午 うま 未 ひつじただし、次のファイルを補助に使って良いこととします。
$ cat eto 子丑寅卯辰巳午未申酉戌亥
A2
$ cat ShellGeiData/vol.41/eto_yomi | python3 -c 'import sys; [print(x[:-1]) for x in sorted(sys.stdin, key = lambda x:open("ShellGeiData/vol.41/eto", "r").read().index(x.split()[0]))]'
子 ね
丑 うし
寅 とら
卯 う
辰 たつ
巳 み
午 うま
未 ひつじ
申 さる
酉 とり
戌 いぬ
亥 い解説
補助ファイルを文字列として持てば、その index でソートすればキレイにできます。ただ上の回答だと、eto_yomi を 1 行読むたびに eto を読み直しているのでファイルが大きくなると遅くなりそうですね。。。
以下のように、先に変数に入れておけば良いですね。
cat ShellGeiData/vol.41/eto_yomi | python3 -c 'import sys; eto = open("ShellGeiData/vol.41/eto", "r").read(); [print(x[:-1]) for x in sorted(sys.stdin, key=lambda x:eto.index(x.split()[0]))]'
Q3
次のファイルのレコードを数字(第一フィールドの計算結果)が小さい順に並べてください。
$ cat kim_calc 1+2+4 金正日 4*3 金正男 3-1-5 金日成 495/3 金正恩 0x1F 金正哲
A3
$ cat ShellGeiData/vol.41/kim_calc | python3 -c 'import sys;[print(x.strip()) for x in sorted(sys.stdin, key=lambda x:eval(x.split()[0]))]' 3-1-5 金日成 1+2+4 金正日 4*3 金正男 0x1F 金正哲 495/3 金正恩
解説
eval() がつよい。
Q4
次のファイルはシフトJISのテキストですが、これを1) 辞書順、2) 数字の小さい順、にソートしてください。出力もシフトJISとします。
$ cat sjis | nkf -g Shift_JIS $ cat sjis | nkf -wLux 123 ずんごるももう 31 こきたてひーひー 9 ほじぱんふんじこみ 2242 たまもとやろう
A4-1
$ python3 -c 'import codecs;[print(x.strip()) for x in sorted(codecs.open("ShellGeiData/vol.41/sjis", "r", "cp932"))]'
123 ずんごるももう
20 ほじぱんふんじこみ
2242 うえってきたかるとらまん
31 こきたてひーひー解説
Python で SJIS のファイルを読み込むにはcodecs.open() を使うか open() に encoding を渡します。
A4-2
$ python3 -c '[print(x.strip()) for x in sorted(open("ShellGeiData/vol.41/sjis", "r", encoding="cp932"), key=lambda x:int(x.split()[0]))]'
20 ほじぱんふんじこみ
31 こきたてひーひー
123 ずんごるももう
2242 うえってきたかるとらまん解説
Python では全角の数字を int にキャストできるようです。すごい。Q5
サイズの小さい順にソートしてください。
$ cat size 2GB 1.2GB 40000MB 1000000000kB 0.4GB 410MB
A5
$ cat ShellGeiData/vol.41/size | python3 -c 'import sys; d = {"k":1,"m":2,"g":3}; [print(x.strip()) for x in sorted(sys.stdin, key=lambda x:eval("".join([j.replace(i,"*1000" * d[i]) if i in j else "" for j in [x[:-2].lower()] for i in d.keys()])))]'
0.4GB
410MB
1.2GB
2GB
40000MB
1000000000kB解説
SI 接頭辞をディクショナリで定義して (d = {"k":1,"m":2,"g":3})、その値の数 "*1000" をつけたものを eval() しています。想像しにくいように思うので、 eval() で計算する前の文字列を出力したものを以下に貼ります。(改行していますが cat ~ ()])))]' までコピペで動きます。)
$ cat ShellGeiData/vol.41/size | python3 -c 'import sys; d = {"k":1,"m":2,"g":3}; [print(x.strip()) for x in sorted(sys.stdin, key=lambda x:
print("".join([j.replace(i,"*1000" * d[i]) if i in j else "" for j in [x[:-2].lower()] for i in d.keys()])) or
eval("".join([j.replace(i,"*1000" * d[i]) if i in j else "" for j in [x[:-2].lower()] for i in d.keys()])))]'
2*1000*1000*1000
1.2*1000*1000*1000
40000*1000*1000
1000000000*1000
0.4*1000*1000*1000
410*1000*1000
0.4GB
410MB
1.2GB
2GB
40000MB
1000000000kB途中で出てくる for j in [x[:-2].lower()] はリスト内包表記内で変数を使う方法です。
Q7
次のローマ数字をソートしてください。
$ cat roman IV XI LXXXIX IX XLIII XX VIII
A7
$ cat ShellGeiData/vol.41/roman | python3 -c 'import sys;d={"I":1,"V":5,"X":10,"L":50};[print(x[:-1]) for x in sorted(sys.stdin, key=lambda x:eval("+".join([[a[j]+"*-1" if j < len(a) - 1 and a[j] < a[j+1] else a[j] for j in range(len(a))] for a in [[str(d[i]) for i in x[:-1]]]][0])))]'
IV
VIII
IX
XI
XX
XLIII
LXXXIX解説
A5 と大きく変わっていません。IVやXL などの減算則の部分に "*-1" をつける処理 ([a[j]+"*-1" if j < len(a) - 1 and a[j] < a[j+1] else a[j] for j in range(len(a))]) が主な違いです。
Q8
次のファイルを辞書順にソートしてください。ただし、濁点がついているものが先に来るようにしてください。できる人はワンライナー中で「かきくけこがぎぐげご」の文字を使わないでください。
$ cat gagigugego かき氷 ぎ・おなら吸い込み隊 きつねうどん ぐりこもりなが事件 きききりん がきの使い くその役にも立たない げんしりょく発電 ごりらいも こじんてきにはクソ
- 例
がきの使い かき氷 ぎ・おなら吸い込み隊 きききりん きつねうどん ぐりこもりなが事件 くその役にも立たない げんしりょく発電 ごりらいも こじんてきにはクソ
A8
$ cat ShellGeiData/vol.41/gagigugego | python3 -c 'import sys; from unicodedata import normalize; c=u"\U00003099"; [print(x[:-1]) for x in sorted(sys.stdin, key=lambda x:["".join(c in a and a.insert(a.index(c), u"\U00000000") or a) for a in [[i for i in normalize("NFD",x)]]])]'
がきの使い
かき氷
ぎ・おなら吸い込み隊
きききりん
きつねうどん
ぐりこもりなが事件
くその役にも立たない
げんしりょく発電
ごりらいも
こじんてきにはクソ解説
Python だとunicodedata.normalize()で Unicode 正規化できます。そのままソートすると期待どおりにソートされないので、濁点 (u"\U00003099") の前に小さな値 (u"\U00000000") を追加してソートしています。
改訂
- A8.
a[a.index(c):]+[u"\U00000000"] + a[:a.index(c)]->a.insert(a.index(c), u"\U00000000") - A2.
[j for j in [i for i in open("ShellGeiData/vol.41/eto", "r")][0]]->[i for i in open("ShellGeiData/vol.41/eto", "r")][0] - A1.
lambda x:("%%%"+x[1])[:-4]->lambda x:("%%%"+x[1])[-4:]
eban on Twitter: "最後は[-4:]じゃないでしょうか?… "
- 全体.
sorted([i for i in sys.stdin], key=->sorted(sys.stdin, key= - まとめを追加
- A2.
[i for i in open("ShellGeiData/vol.41/eto", "r")][0]->open("ShellGeiData/vol.41/eto", "r").read() - A5. SI接頭辞をディクショナリで定義して汎用性を上げました
- 前.
cat ShellGeiData/vol.41/size | python3 -c 'import sys;[print(x.strip()) for x in sorted(sys.stdin, key=lambda x:eval(x[:-2].replace("k","*1000").replace("M","*1000"*2).replace("G","*1000"*3)))]' - 後.
cat ShellGeiData/vol.41/size | python3 -c 'import sys; d = {"k":1,"m":2,"g":3}; [print(x.strip()) for x in sorted(sys.stdin, key=lambda x:eval("".join([j.replace(i,"*1000" * d[i]) if i in j else "" for j in [x[:-2].lower()] for i in d.keys()])))]'
- 前.
- A7. 減算則が適用されるのが、最初にある場合のみになっていたのを修正しました。 (
LXXXIXが 89 ではなく 91 に計算されていた。)- 前.
eval("+".join([[a[0]+"*-1"]+a[1:] if a[0] < a[1] else a for a in [[str(d[i]) for i in x[:-1]]]][0])) or x - 後.
eval("+".join([[a[j]+"*-1" if j < len(a) - 1 and a[j] < a[j+1] else a[j] for j in range(len(a))] for a in [[str(d[i]) for i in x[:-1]]]][0]))
- 前.
- 解説を追加
