2019年7月11日木曜日

連番を振る、等差数列

箇条書きの項目に行番号を振りたいときなどに役立つ知識。
一般化して、等差数列の作り方。

One to Ten
Generate the sequence of numbers from 1 to 10, one number per line. Inspired by this Reddit thread: https://redd.it/ak4it2

問題

何もない状態から、以下の連番を作成せよ。

1
2
3
4
5
6
7
8
9
10

愚直にやると

この問題に出会うまでは、マクロと変数を使ったアプローチしか思いつかなかった。
例えば、以下のようなものである。

:let i=1<CR>qqi<C-R>=i<CR><Esc>:let i=i+1<CR>o<Esc>q9@qddZZ
  1. :let i=1<CR>
    変数iを初期化する。
  2. qq
    マクロの記録を開始する。
  3. i<C-R>=i<CR><Esc>
    インサートモードに入り、変数iの値をエクスプレッションレジスタ(:help c_CTRL-R)経由で挿入し、ノーマルモードに戻る。
  4. :let i=i+1<CR>
    変数iをインクリメントする。
  5. o<Esc>
    空白の一行を下に挿入する。
  6. q
    マクロの記録を停止する。
  7. 9@qddZZ
    マクロを9回実行し、余分な一行を削除したのち、ファイルを保存して終了する。

この方法の良い点は、いかなる数列に対しても同様の手順で作成できる点である。
しかし、たかが連番にマクロと変数操作を用いるのは大げさである。
スコアはお察し。

解説

現時点での最善の方法は以下である。
i0<Esc>Y9Pv}g<C-A>ZZ

このスマートな回答のスコアは12点である。

  1. i0<Esc>
    0を挿入する。
  2. Y9P
    一行目、すなわち「0」をコピーし9回貼り付ける。
    なお、同じようでもY9pとしてしまうと、貼り付けが終わったときにカーソルが2行目に移動してしまう。
  3. v}
    一行目から末尾まで選択する。
  4. g<C-A>
    連番を作成する。
  5. ZZ
    ファイルを保存して終了。

原理

最初に1をずらっと並べて、次にビジュアルモードで選択し、最後にg<C-A>とすることで連番を作成できる。
なぜこのようなことが可能なのだろうか。

Vimのhelpを見てみよう(:help v_CTRL-A、:help v_g_CTRL-A)

==================================================
*v_CTRL-A*
{Visual}CTRL-A
Add [count] to the number or alphabetic character in the highlighted text.  {not in Vi}

*v_g_CTRL-A*
{Visual}g CTRL-A
Add [count] to the number or alphabetic character in the highlighted text. If several lines are highlighted, each one will be incremented by an additional [count] (so effectively creating a [count] incrementing sequence).  {not in Vi}

For Example, if you have this list of numbers:
1. ~
1. ~
1. ~
1. ~
Move to the second "1." and Visually select three lines, pressing g CTRL-A results in:
1. ~
2. ~
3. ~
4. ~
==================================================

例に倣って考えてみる。
矩形選択で <CTRL-A> とした場合は、helpの例で表すと次のようになる。
1. ~ → 2. ~
1. ~ → 2. ~
1. ~ → 2. ~
1. ~ → 2. ~

一方で、矩形選択で g<CTRL-A> とした場合には、次のようになる。
1. ~ → 1. ~ (+1) = 2. ~
1. ~ → 1. ~ (+2) = 3. ~
1. ~ → 1. ~ (+3) = 4. ~
1. ~ → 1. ~ (+4) = 5. ~

(+n) は "additional"、連番を実現できる所以である。

そして[count]を指定した場合、例えば 5g<CTRL-A> とした場合には、次のようになる。

1. ~ → 1. ~ (+1+1+1+1+1) = 6. ~
1. ~ → 1. ~ (+2+2+2+2+2) = 11. ~
1. ~ → 1. ~ (+3+3+3+3+3) = 16. ~
1. ~ → 1. ~ (+4+4+4+4+4) = 21. ~

分かりやすく書きなおすと、
1. ~ → 1. ~ (+1 * 5) = 6. ~
1. ~ → 1. ~ (+2 * 5) = 11. ~
1. ~ → 1. ~ (+3 * 5) = 16. ~
1. ~ → 1. ~ (+4 * 5) = 21. ~

となる。

これは、初項6、公差5の等差数列に他ならない。



0 件のコメント:

コメントを投稿

コメント表示は承認制に設定しています