ランダムかつ重複しないように文字列を生成する(Ruby)

あることのために必要だったので、複数の文字列をランダムかつ重複しないように生成するメソッドを書いてみました。

こんな感じです。

$ irb
irb(main):001:0> require_relative "generate_random_strings"
=> true
irb(main):002:0> Utils.generate_random_strings(40)
=> ["kk", "cm", "aq", "vf", "zf", "uh", "qv", "pv", "bb", "jp", "td", "ri", "mr",
    "hq", "gy", "pe", "ta", "ot", "ob", "km", "zu", "cz", "sf", "qo", "zt", "uq",
    "tc", "fd", "xq", "ki", "po", "w", "dj", "ks", "mw", "am", "zr", "az", "iy", "gv"]

重複しない 40個の文字列(アルファベット小文字)が生成されて Array で返ります。文字の長さは最小になるようになっているので、長さ 1 と 2 の文字列が入り混じっています。

文字列の長さを指定して呼ぶこともできます。

irb(main):003:0> Utils.generate_random_strings(40, 4)
=> ["bakz", "aipi", "prgo", "cwfw", "qqkv", "lgtt", "neid", "jjjz", "cjst", "tdfd",
    "sguf", "nkqk", "bvpl", "tldk", "qszi", "qfvj", "mnjy", "epsd", "abix", "ldap",
    "lijm", "jqzl", "gclu", "fxxe", "tcxc", "rayu", "rcsn", "aitp", "focj", "ngxd",
    "ouxc", "reze", "svxc", "ppaz", "roeb", "qgdt", "mhdw", "ewap", "fxjb", "mmrx"]

長さ 4 のランダムな文字列が 40個返りました。


コード。
generate_random_strings.rb

module Utils
  def repeated_permutation(a, b)
    a ** b
  end
  
  def generate_random_strings(num, string_length = nil)
    table = [*"a".."z"]
    limit = [0, 26, 702, 18278, 475254, 12356630]
    result = []
    generate_string1 = ->(n, l) {
      st = ""
      l.times do
        a, n = n % 26, n / 26
        st = table[a] + st
      end
      st
    }
    generate_string2 = ->(n) {
      idx = limit.find_index {|i| i > n}
      generate_string1.(n - limit[idx - 1], idx)
    }
        
    if string_length and 26 < string_length
      raise "Given length of strings too big."
    end
    
    num_table = Set.new
    if string_length
      n = Utils.repeated_permutation(26, string_length)
      raise "Given length of strings too small." if n < num
      while num_table.size < num
        num_table << rand(n)
      end
      num_table.each {|i| result << generate_string1.(i, string_length)}
    else
      idx = limit.find_index {|i| i >= num}
      raise "Result Array too big." unless idx
      while num_table.size < num
        num_table << rand(limit[idx])
      end
      num_table.each {|i| result << generate_string2.(i)}
    end
    result
  end
  module_function :repeated_permutation, :generate_random_strings
end

 

Gem 化

Gem 'kaki-utils' に同梱しました。$ gem install kaki-utils や Bundler でインストールできます。

$ bundle exec irb
irb(main):001:0> require 'kaki/utils'
=> true
irb(main):002:0> Utils.generate_random_strings(40)
=> ["qv", "kj", "wf", "ch", "ds", "hp", "ro", "oj", "xa", "dz", "vv", "zz", "fh",
    "rf", "tr", "gw", "cf", "yx", "ep", "pr", "tl", "sn", "ar", "ao", "ij", "pl", "my",
    "gy", "sk", "yk", "to", "hq", "wj", "vf", "jh", "pu", "cg", "gq", "wu", "dx"]

みたいな感じ。