いきなりですが問題です.
引数(文字列)を一つとり,その文字を並べ替えてできる文字列(引数自身を含む)が何通りあるかを求めるプログラムを作りなさい.
順列の問題ですので,まずは順列 - Wikipediaを見ます.「重複を許す場合」の中に,分母が階乗の積で,分子が一つの階乗になっている式があり,これが使えそうです.例を出すと,もとの文字列が wakayama だったら,w, a, k, y, mの各文字から,aのみ4個,それ以外は1個ずつ使ってできる文字列なので,となります.
階乗を再帰呼び出しで求めるのは,好きではありません.しかし,whileループ*1というのも泥臭いです.そういえば,Enumerable#injectが使えるかもしれません.そこの例では配列に対して使っていますが,Rangeも,Enumerableをmix-inしているので,いけそうです.もう少し探すと,http://konohaotoshi.blog69.fc2.com/blog-entry-103.htmlというのも見つかりました.
もう一点,考慮すべきことは,答えの後で.
#!/usr/bin/env ruby # permutation_count.rb require 'strscan' def factorial(num) (1..num).inject(1) {|result, i| result * i} end def permutation_count(str) str = str.split(//u).sort.join('') t = factorial(str.length) ss = StringScanner.new(str) while !ss.eos? t /= factorial(ss.scan(/(.)\1*/u).length) end t end str = ARGV.shift || 'ABCD' puts "#{str}: #{permutation_count(str)}"
実行してみます.
$ ruby permutation_count.rb wakayama wakayama: 1680 $ ruby permutation_count.rb takehiko takehiko: 20160 $ ruby permutation_count.rb 12345678 12345678: 40320 $ ruby permutation_count.rb takehikom takehikom: 181440 $ ruby permutation_count.rb wakayama-u wakayama-u: 151200
さて,「答えの後で」の解説です.wakayama の例で「aのみ4個」と書きましたが,文字列から,各文字の個数をどうやって求めるかです.
1文字ずつ順に求めるのはスマートではないなと思いまして,strscanライブラリを使ってみました.あらかじめ文字をソートしておけば,1文字以上の連続する同じ文字の並びが「/(.)\1*/」という正規表現で求められます.