Comma Quibbling
September 22, 2017
Eric Lippert, at his blog Fabulous Adventures in Coding, discusses the problem of comma quibbling, which turns a list of words like (“ABC” “DEF” “G” “H”) into the string “ABC, DEF, G and H” with commas between each pair of words except the last pair, which gets the word “and” (without a comma). Here are the rules:
- If the input is empty, so is the output.
- If the input has a single word, so does the output.
- If the input has two words, the output is the two words separated by “and”.
- If the input has more than two words, the output is all the words, separated by commas, but with the last comma replaced by “and”.
A word is a maximal sequence of characters not containing a comma or a space.
Your task is to write a function that adds commas to a list of words, using the rules described above. When you are finished, you are welcome to read or run a suggested solution, or to post your own solution or discuss the exercise in the comments below.
Quick one in perl using regexs….
MUMPS/Cache
f i=”a”,”a b”,”a b cd e f g” w !,i,?15,$$quibble^zjsg(i)
a a
a b a and b
a b cd e f g a,b,cd,ef and g
Here’s a solution in Python.
Output:
I didn’t read rule 4 carefully. With more than two words, I was outputting a comma between the last words, as opposed to “and”. Here’s an updated solution.
Here’s a Python solution that follows the requirement in the original blog, to only use the ability to enumerate the input (in Python terms, the function allows any iterator).
In modern versions of Python, it’s possible to use extended tuple unpacking to do this much more simply:
This needs some special casing for the 0 and 1 element sequence cases, which I’ve omitted (trap ValueError for the 0-element case, and check for an empty head for the 1-element case).
A direct translation of the rules into Haskell.
Can someone explain why in C# (1) is O(N^2) but (2) is O(N)?
string[] x = an array of length N
string result = “”;
for(int i = 0; i < N; i++)
result = result + “, ” + x[i];
2.
string[] x = an array of length N
string result = String.Join(“, “, x);
Basically, with (1), every time you do result = result + “, ” + x[i] you are reallocating result, which means a copy of everything you’ve created so far. So, you copy the whole string N times, and the string is length N (technically, you’re copying items of length 1, 2, … N, so the average length is N/2, but a constant factor doesn’t affect the result).
With (2) you allocate the string once, at the end, avoiding the recopying.