エンジニアのソフトウェア的愛情

または私は如何にして心配するのを止めてプログラムを・愛する・ようになったか

いかにして表計算の列名をつくるか・補遺・その補遺

おさらい。

最終形態

先日、Haskellで無限長配列を生成する例を挙げました。

再掲。

import Data.List(group)

column_names_ :: [String] -> [String]
column_names_ ss = ss ++ (map concat $ sequence [column_names_ ss, ss])

column_names :: [String]
column_names = column_names_ $ group ['A'..'Z']
drop 20 $ take 30 column_names
    -- => ["U","V","W","X","Y","Z","AA","AB","AC","AD"]


ほぼ同じ方法でRubyで書いた例も挙げました。

こんな感じ。

([*'A'..'Z'] + [*'A'..'Z'].product([*'A'..'Z']).map(&:join)).first(30).drop(20)
    # => ["U", "V", "W", "X", "Y", "Z", "AA", "AB", "AC", "AD"]

ここで。実は。Rubyのばあい、連結などということをしなくても実現できること、その後に知りました。

こんな感じ。

[*'A'..'ZZ'].first(30).drop(20)
    # => ["U", "V", "W", "X", "Y", "Z", "AA", "AB", "AC", "AD"]


演算子..はメソッドsuccが定義されていれば利用できるため、加えて'Z'の次は'AA'と定義されているため、'A'から'ZZ'までを範囲として扱うことができることになるわけです。

ただ[*'A'..'ZZ']という書き方をすると、範囲を配列に変換してしまうので、小さい範囲しか必要でなくても配列全体を生成してしまいます。


これも、配列に変換せず、範囲式のまま扱うことで解決することができるのでした。

こんな感じ。

('A'..'ZZ').first(30).drop(20)
=> ["U", "V", "W", "X", "Y", "Z", "AA", "AB", "AC", "AD"]


おおざっぱな計算をすると、1桁から14桁までの文字列を利用できれば、263を表現するに充分なので、次のようなメソッドを用意すればだいたいにおいて事足りることになります。

# start 番目の文字から length 個の文字を配列として取得する
def column_names(start, length)
  ('A'..'ZZZZZZZZZZZZZZ').first(start + length).drop(start)
end
column_names(0, 10)
    # => ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J"]
column_names(20, 10)
    # => ["U", "V", "W", "X", "Y", "Z", "AA", "AB", "AC", "AD"]

結論

Rubyを使いましょう。



…そんな感じで。