Mathematica, 72 65 61 bytes
Print@@@Tuples@{a=##/(b=#5#9#15#21#25#)&@@Alphabet[],b,a,b,a}
For testing, I recommend replacing Print@@@
with ""<>#&/@
. Mathematica will then display a truncated form showing the first few and last few words, instead of taking forever to print 288,000 lines.
Explanation
I finally found a use for dividing strings. :)
I've been intrigued by the possibility of adding or multiplying strings for a while, but the actual use cases are fairly limited. The main point is that something like "foo"+"bar"
or "foo"*"bar"
(and consequently, the short form "foo""bar"
) is completely valid in Mathematica. However, it doesn't really know what to do with the strings in arithmetic expressions, so these things remain unevaluated. Mathematica does apply generally applicable simplifications though. In particular, the strings will be sorted into canonical order (which is fairly messed up in Mathematica, once you start sorting strings containing letters of various cases, digits and non-letters), which is often a dealbreaker, but doesn't matter here. Furthermore, "abc""abc"
will be simplified to "abc"^2
(which is a problem when you have repeated strings, but we don't have that either), and something like "abc"/"abc"
will actually cancel (which we'll be even making use of).
So what are we trying to golf here. We need a list of vowels and a list of consonants, so we can feed them to Tuples
to generate all possible combinations. My first approach was the naive solution:
Characters@{a="bcdfghjklmnpqrstvwxz",b="aeiouy",a,b,a}
That hardcoded list of consonants does hurt a bit. Mathematica does have an Alphabet
built-in which would allow me to avoid it, if I were able to remove the vowels in a cheap way. This is where it gets tricky though. The simplest way to remove elements is Complement
, but that ends up being longer, using one of the following options:
{a=Complement[Alphabet[],b=Characters@"aeiouy"],b,a,b,a}
{a=Complement[x=Alphabet[],b=x[[{1,5,9,15,21,25}]]],b,a,b,a}
(Note that we don't need to apply Characters
to the whole thing any more, because Alphabet[]
gives a list of letters, not a string.)
So let's try that arithmetic business. If we represent the entire alphabet as a product of letters instead of a list, then we can remove letters by simple division, due to the cancelling rule. That saves a lot of bytes because we won't need Complement
. Furthermore, "a""e""i""o""u""y"
is actually a byte shorter than Characters@"aeiouy"
. So we do this with:
a=##/(b="a""e""i""o""u""y")&@@Alphabet[]
Where we're storing the consonant and vowel products in a
and b
, respectively. This works by writing a function which multiplies all its arguments with ##
and divides them by the product of vowels. This function is applied to the alphabet list, which passes each letter in as a separate argument.
So far so good, but now we have
{a=##/(b="a""e""i""o""u""y")&@@Alphabet[],b,a,b,a}
as the argument to Tuples
, and those things are still products, not lists. Normally, the shortest way to fix that is putting a List@@@
at the front, which turns the products into lists again. Unfortunately, adding those 7 bytes makes it longer than the naive approach.
However, it turns out that Tuples
doesn't care about the heads of the inner lists at all. If you do
Tuples[{f[1, 2], f[3, 4]}]
(Yes, for an undefined f
.) You'll get:
{{1, 3}, {1, 4}, {2, 3}, {2, 4}}
Just as if you had used a List
instead of f
. So we can actually pass those products straight to Tuples
and still get the right result. This saves 5 bytes over the naive approach using two hardcoded strings.
Now the "a""e""i""o""u""y"
is still fairly annoying. But wait, we can save a few bytes here as well! The arguments of our function are the individual letters. So if we just pick out the right arguments, we can reuse those instead of the string literals, which is shorter for three of them. We want arguments #
(short for #1
), #5
, #9
, #15
, #21
and #25
. If we put #
at the end, then we also don't need to add any *
to multiply them together, because (regex) #\d+
is a complete token that can't have any non-digit appended to it. Hence we end up with #5#9#15#21#25#
, saving another 4 bytes.
7I see two things here. First, there are a ridiculous amount of words like this. How do you expect to test the entries? Also, there are many names that fit that constraint. The first that comes to mind is Jacob, although others like Lucas also fit – TrojanByAccident – 2017-01-12T12:10:06.007
9@TrojanByAccident I believe the challenge requires all possible matching letter combinations, regardless of whether they are names/English words. "Words don't have to be actual dictionary words." – trichoplax – 2017-01-12T12:22:58.177
@trichoplax if you mean my second point, I was referring to the OP's Note at the bottom – TrojanByAccident – 2017-01-12T12:24:03.970
@TrojanByAccident My apologies - I didn't realise they were separate points. In that case, I guess a program to test the outputs would be helpful. I make it 20620620=288,000 words in total, around 1,728,000 characters including delimiters. I'm not sure if a Stack Snippet can handle strings that long. – trichoplax – 2017-01-12T12:28:51.067
@TrojanByAccident The note was just to point out how I had the idea for the question, not an extra challenge. Also, my first name is Kevin :) – wilks – 2017-01-12T12:39:14.047
Does the order in which the names are output, matter? If so, can you please explain that order in more detail? – smls – 2017-01-12T12:48:05.380
@smls By incremental I mean that after babaz comes babeb, not babob or babib. So we work our way through vowels and consonants in the order they come in the alphabet. – wilks – 2017-01-12T12:50:11.987
Can we use uppercase instead of lowercase? – Adám – 2017-01-12T13:28:52.583
Can we return a list of strings instead? – Adám – 2017-01-12T13:29:57.590
@Adám The output should be formatted like in the example, lowercase, each word to its line, no repeats. – wilks – 2017-01-12T13:40:17.007
3
@wilks Relevant meta post -- Strict i/o formats aren't appreciated in this SE community. This challenge is focusing on generating c-v-c-v-c words, not inserting newlines between words, no?
– JungHwan Min – 2017-01-12T14:41:37.9331@JungHwanMin Thanks for the link, first time here and I didn't know about this. I saw it as a readable and alphabetical list of all the c-v-c-v-c words. So I agree that upper or lowercase really doesn't matter, but I also think that one very long string or, say some nested arrays, whilst technically valid wouldn't be a great answer. – wilks – 2017-01-12T15:30:32.413
2Having run a few of the upvoted answers to this question, they obviously do not comply with "The output should be incremental with each word on its own line". Has this requirement been relaxed and if so can you edit the question to reflect this? I reckon I could lose quite a few bytes if my answer wasn't restricted by the format. – ElPedro – 2017-01-12T18:33:26.250