Goal: Create a combination of emails based from inputted first name, last name, middle name, and a domain. Add in common separators. Then I'll check which one is correct with the rapportive API. This is the first part of the bigger script.
If you are given the string
variables
{fn}
{ln}
{fi}
{li}
{mi}
{mn}
How would you create the following?
{fn}
{ln}
{fn}{ln}
{fn}.{ln}
{fi}{ln}
{fi}.{ln}
{fn}{li}
{fn}.{li}
{fi}{li}
{fi}.{li}
{ln}{fn}
{ln}.{fn}
{ln}{fi}
{ln}.{fi}
{li}{fn}
{li}.{fn}
{li}{fi}
{li}.{fi}
{fi}{mi}{ln}
{fi}{mi}.{ln}
{fn}{mi}{ln}
{fn}.{mi}.{ln}
{fn}{mn}{ln}
{fn}.{mn}.{ln}
{fn}-{ln}
{fi}-{ln}
{fn}-{li}
{fi}-{li}
{ln}-{fn}
{ln}-{fi}
{li}-{fn}
{li}-{fi}
{fi}{mi}-{ln}
{fn}-{mi}-{ln}
{fn}-{mn}-{ln}
{fn}_{ln}
{fi}_{ln}
{fn}_{li}
{fi}_{li}
{ln}_{fn}
{ln}_{fi}
{li}_{fn}
{li}_{fi}
{fi}{mi}_{ln}
{fn}_{mi}_{ln}
{fn}_{mn}_{ln}
at the moment I am solving it by creating an array
for each permutation
fi_perms = [fi].product ['_' + li,
'_' + ln,
'-' +li,
'-' ln,
'.' + li,
'.' + ln,
li,
ln,
mi '_' ln,
mi '-' ln,
mi + '.' + ln,
mi + ln]
fn_perms = [fn].product ['_' + li,
'_' + ln,
'_' + mi '_' + ln,
'_' + mn '_' + ln,
'-' + li,
'-' + ln,
'-' + mi + '-' + ln,
'-' + mn + '-' ln,
'.' + li,
'.' + ln,
'.' + mi '.' +ln,
'.' + mn '.' ln,
li,
ln,
mi + ln,
ln,
mi + ln,
mn + ln]
li_perms = [li].product ['_' + fi,
'_' + fn,
'-' + fi,
'-' + fn,
'.' + fi,
'.' + fn,
fi,
fn]
ln_perms = [ln].product [ln,
'_' + fi,
'_' + fn,
'-' + fi,
'-' + fn,
'.' + fi,
'.' + fn,
fi,
fn]
because I will be using it later by adding it to another array like so
perms = li_perms + ln_perms + fi_perms + fn_perms
permutations = []
perms.count.times do |i|
perms.each do |perm|
permutations[i] = perm.join
end
end
permutations[0] = ['fn.mn.ln']
Is there a better of doing this?
2 Answers 2
Since your list is not "all permutation", but is painstakingly built by hand, I would not suggest using array's permutation
API or something like that, but keep the curated mode you are using.
I would suggest building it in a more readable way. In your way of [fi].product[...]
it is very hard to follow which permutation exists, and which doesn't. The first list you show is more readable, and if you name your atoms correctly (first_name
instead of fn
), it makes it trivial to understand what you are trying to do. I would suggest building your permutation table as a string like this:
name_permutations = <<PERMS
{last_initial}{first_name}
{last_initial}.{first_name}
{last_initial}{first_initial}
{last_initial}.{first_initial}
{first_initial}{middle_initial}{last_name}
{first_initial}{middle_initial}.{last_name}
{first_name}{middle_initial}{last_name}
{first_name}.{middle_initial}.{last_name}
{first_name}{middle_name}{last_name}
{first_name}.{middle_name}.{last_name}
{first_name}-{last_name}
{first_initial}-{last_name}
{first_name}-{last_initial}
{first_initial}-{last_initial}
{last_name}-{first_name}
{last_name}-{first_initial}
{last_initial}-{first_name}
{last_initial}-{first_initial}
...
PERMS
And then use substitutions to get all permutations:
name_permutations.gsub('{first_name}', first_name)
.gsub('{last_name}', last_name)
.gsub('{middle_name}', middle_name)
.gsub('{first_initial}', first_initial)
.gsub('{middle_initial}', middle_initial)
.gsub('{last_initial}', last_initial)
.split($/)
-
\$\begingroup\$ I like this approach for the question posed, although I think the all possible permutations of names, initials, and separators is a more interesting problem. \$\endgroup\$Jonah– Jonah2014年03月08日 06:55:57 +00:00Commented Mar 8, 2014 at 6:55
-
1\$\begingroup\$ @Jonah - For that you could
(1..9).map{ |i| [fi,fn,mi,mn,li,ln,'.','-','_'].permutations(i).map(&:join) }.flatten
(ruby-doc.org/core-2.1.1/Array.html#method-i-permutation) \$\endgroup\$Uri Agassi– Uri Agassi2014年03月08日 07:29:56 +00:00Commented Mar 8, 2014 at 7:29 -
\$\begingroup\$ Good point that's clever \$\endgroup\$Jonah– Jonah2014年03月08日 14:34:17 +00:00Commented Mar 8, 2014 at 14:34
-
\$\begingroup\$ @UriAgassi just a minor error that
permutations
should be singularpermutation
\$\endgroup\$Patrick– Patrick2014年03月10日 03:35:53 +00:00Commented Mar 10, 2014 at 3:35
Edit: I've made some changes to try to improve the readability of my answer.
You could just create a few simple helper methods. Here's an example, based on the assumption that ordering is not important. Rather than the usual approach of presenting the code and then showing how it is used, I have reversed those steps, as the code is so simple that most readers will be able to glean it merely from its application.
There are two helper methods, gen
and middle_with_seps
, The variables fn
, mn
and ln
refer to "first name", "middle name" and "last name". The first, middle and last initials are: fi = fn[0]
, mi = mn[0]
and li = ln[0]
. The constants should be self-explanatory. (The application of the code is best appreciated when one of these is playing in the background.)
Application
fn, mn, ln = 'Wild', 'Bill', 'Hickok'
gen([fn, fi], DASH_USCORE , [ln, li] ) +
gen([ln, li], DASH_USCORE , [fn, fi] ) +
gen(li , DOT , fn ) +
gen(li , NOSPACE_DOT , fi ) +
gen(fn , middle_with_seps(mi, DASH_USCORE + NOSPACE_DOT), ln ) +
gen(fn , middle_with_seps(mn, DASH_USCORE + NOSPACE_DOT), ln ) +
gen(fi , middle_with_seps(mi, DASH_USCORE + NOSPACE) , ln ) +
gen(fi , middle_with_seps(mi+'.', NOSPACE) , ln )
#=> ["Wild_Hickok", "Wild_H", "Wild-Hickok", "Wild-H",
# "W_Hickok", "W_H", "W-Hickok", "W-H",
# "Hickok_Wild", "Hickok_W", "Hickok-Wild", "Hickok-W",
# "H_Wild", "H_W", "H-Wild", "H-W",
# "H.Wild", "HW", "H.W",
# "Wild_B_Hickok", "Wild-B-Hickok", "WildBHickok", "Wild.B.Hickok",
# "Wild_Bill_Hickok", "Wild-Bill-Hickok","WildBillHickok","Wild.Bill.Hickok",
# "W_B_Hickok", "W-B-Hickok", "WBHickok",
# "WB.Hickok"]
Code
NOSPACE = ['']
DOT = ['.']
NOSPACE_DOT = NOSPACE + DOT
DASH_USCORE = ['-', '_']
fi, mi, li = fn[0], mn[0], ln[0]
def combine_strings(s1, s2, s3) "#{s1}#{s2}#{s3}" end
def gen(left_strings, seps, right_strings)
left_strings = [left_strings].flatten
seps = [seps].flatten
right_strings = [right_strings].flatten
left_strings.each_with_object([]) { |l,a| seps.each { |sep|
right_strings.each { |r| a << combine_strings(l, sep, r) } } }
end
def middle_with_seps(m, seps)
seps.each_with_object([]) { |s,a| a << combine_strings(s, m, s) }
end
Explanation
gen()
's arguments are as follows:
left_strings
: an array of strings for the left end of the stringseps
: an array of separators (e.g., '', '.', '-', etc.)right_strings
: an array of strings for the right end of the string
If left_strings
, seps
or right_strings
is entered as a string, rather than an array of strings, it is converted to an array containing itself. gen
constructs an array of strings, one for each combination of strings taken from left_strings
, seps
and right_strings
.
middle_with_seps
's arguments are as follows:
m
is the middle name or initialseps
is the same as for the methodgen
middle_with_seps
creates an array of separators that is passed as the argument seps
in gen()
when the middle name or initial is to be included. Each element of that array is the (string) value of m
bracketed by a separator (except in one case where the initial 'B'
is converted to 'B.'
('WB.Hickok'
). For example,
middle_with_seps(mi, DASH_USCORE + NOSPACE) #=> ["_B_", "-B-", "B"]
-
\$\begingroup\$ Why are you giving such unreadable names to your variables and functions? Your code is very hard to read, and you need to tell us the
la
is an array for the left end of the string, instead of calling itleft_end_strings
or something more meaningful - this is code-review, after all... \$\endgroup\$Uri Agassi– Uri Agassi2014年03月16日 07:08:57 +00:00Commented Mar 16, 2014 at 7:08 -
\$\begingroup\$ @Uri, there was a method to my madness, even if I have miscalculated, as I appear to have done (for the author of code is usually not the best one to judge its readability). My intent was for the lines beginning
gen([fn, fi], ['_', '-']...
to tell the reader at a glance what the two helpers did. That wouldn't have worked if I hadgenerate_combinations([first_name, last_name], ['_', '-']...
as lines would have wrapped or required horizontal scrolling, defeating the purpose. I've made some changes to my answer. I welcome suggestions for further improvement. Thanks. \$\endgroup\$Cary Swoveland– Cary Swoveland2014年03月16日 18:54:42 +00:00Commented Mar 16, 2014 at 18:54
{fn}{mi}{ln}
be{fn}.{mi}{ln}
? and is the order required in that way exactly? \$\endgroup\$