Comma quibbling: Difference between revisions
Content deleted Content added
Thundergnat (talk | contribs) m →{{header|Pascal}}: fix markup |
→Nu: add |
||
(31 intermediate revisions by 15 users not shown) | |||
Line 1:
{{task}}
Comma quibbling is a task originally set by Eric Lippert in his [
Line 13:
<br>
Test your function with the following series of inputs showing your output here on this page:
* []
* ["ABC"]
* ["ABC", "DEF"]
Line 20:
<br>
Note: Assume words are non-empty strings of uppercase characters for this task.
{{Template:Strings}}
<br><br>
Line 131 ⟶ 134:
=={{header|8080 Assembly}}==
<syntaxhighlight lang="8080asm"> org 100h
jmp demo
Line 223 ⟶ 225:
{ABC and DEF}
{ABC, DEF, G and H}</pre>
=={{header|ABC}}==
<syntaxhighlight lang="ABC">HOW TO RETURN quibble words:
PUT "" IN result
PUT #words IN remaining
FOR word IN words:
PUT result^word IN result
PUT remaining-1 IN remaining
IF remaining = 1: PUT result^" and " IN result
IF remaining > 1: PUT result^", " IN result
RETURN "{" ^ result ^ "}"
PUT {} IN tests
INSERT {} IN tests
INSERT {[1]: "ABC"} IN tests
INSERT {[1]: "ABC"; [2]: "DEF"} IN tests
INSERT {[1]: "ABC"; [2]: "DEF"; [3]: "G"; [4]: "H"} IN tests
FOR test IN tests:
WRITE quibble test/</syntaxhighlight>
{{out}}
<pre>{}
{ABC}
{ABC and DEF}
{ABC, DEF, G and H}</pre>
=={{header|Acornsoft Lisp}}==
There's no string data type; symbols are used instead. The <code>implode</code> function is used to concatenate a list of symbols. When writing a symbol in source code, exclamation mark is an escape character that allows characters such as spaces and exclamation marks to be treated as part of the symbol's name.
<syntaxhighlight lang="lisp">
(defun examples ()
(map '(lambda (words) (printc (quibble words)))
'(() (ABC) (ABC DEF) (ABC DEF G H))))
(defun quibble (words)
(implode (list '{ (quibbles words) '})))
(defun quibbles (words)
(implode (conjunction words)))
(defun conjunction (words)
(cond ((null words)
'())
((null (cdr words))
words)
((null (cddr words))
(list (car words) '! and! (cadr words)))
(t
(cons (car words)
(cons ',! (conjunction (cdr words)))))))
</syntaxhighlight>
{{out}}
Calling <code>(examples)</code> will output:
<pre>
{}
{ABC}
{ABC and DEF}
{ABC, DEF, G and H}
</pre>
=={{header|Action!}}==
Line 524 ⟶ 587:
ABC DEF : {ABC and DEF}
ABC DEF G H : {ABC, DEF, G and H}</pre>
=={{header|APL}}==
<syntaxhighlight lang="APL">quibble ← 1⌽'}{',(∊⊢,¨2↓(' and ' ''),⍨(⊂', ')⍴⍨⍴)</syntaxhighlight>
{{out}}
<pre> quibble ⍬
{}
quibble ⊂'ABC'
{ABC}
quibble 'ABC' 'DEF'
{ABC and DEF}
quibble 'ABC' 'DEF' 'G' 'H'
{ABC, DEF, G and H}</pre>
=={{header|AppleScript}}==
Line 723 ⟶ 798:
=={{header|Arturo}}==
<syntaxhighlight lang="rebol">quibble:
-> return "{}"
if? 1 = size sequence
-> return ~"{|sequence\0|}"
last: pop 'sequence
return ~« {|join.with: ", " sequence| and |last|}
]
Line 746 ⟶ 824:
<pre>{}
{ABC}
{ABC
{ABC, DEF, G
=={{header|Astro}}==
Line 1,241 ⟶ 1,319:
{ABC and DEF}
{ABC, DEF, G and H}</pre>
=={{header|Commodore BASIC}}==
The Commodore character set has no curly braces, so I substituted square brackets. The solution could no doubt be improved, but some of the elegance of other solutions is not possible simply because a FOR loop always executes at least once, even if its parameters would seem to indicate that it should not.
<syntaxhighlight lang="basic">100 DIM A$(3)
110 FOR TC=1 TO 4
120 : READ A: IF A=0 THEN 160
130 : FOR I=0 TO A-1
140 : READ A$(I)
150 : NEXT I
160 : GOSUB 200
170 : PRINT CQ$
180 NEXT TC
190 END
200 CQ$="["
210 IF A < 1 THEN 290
220 CQ$ = CQ$ + A$(0)
230 IF A < 2 THEN 290
240 IF A < 3 THEN 280
250 FOR I=1 TO A - 2
260 : CQ$ = CQ$ + ", " + A$(I)
270 NEXT I
280 CQ$ = CQ$ + " AND " + A$(A - 1)
290 CQ$ = CQ$ + "]"
300 RETURN
310 DATA 0
320 DATA 1, ABC
330 DATA 2, ABC, DEF
340 DATA 4, ABC, DEF, G, H
</syntaxhighlight>
{{out}}
<pre>[]
[ABC]
[ABC AND DEF]
[ABC, DEF, G AND H]</pre>
=={{header|Common Lisp}}==
Line 1,346 ⟶ 1,458:
{{out}}
<pre>["{}", "{ABC}", "{ABC and DEF}", "{ABC, DEF, G and H}"]</pre>
=={{header|dc}}==
<syntaxhighlight lang="dc">[(q)uibble: main entry point. print brackets, calling n in between if stack not
empty.]sx
[ [{]n z 0 !=n [}]pR ]sq
[(n)onempty: if more than 1 item, call m. then print top of stack.]sx
[ z 1 !=m n ]sn
[(m)ore: call f to flip stack into r register, call p to print most of it,
then pop the last item back onto the main stack so it's there to be printed
after we return]sx
[ lfx lpx Lr ]sm
[(f)lip: utility routine to reverse the stack into the r register]sx
[ Sr z 0 !=f ]sf
[(p)rint: get next item from stack in r register and print it. If there are
more than 2 items left on the register stack (which never drops below one
item), print a comma (c) and recurse. If there are exactly two items left,
print " and " (a) and return.]sx
[ Lr n 2 yr >c 2 yr =a 2 yr >p]sp
[(c)omma: utility routine to print a comma followed by a space]sx
[ [, ]n ]sc
[(a)and: utility routine to print " and "]sx
[ [ and ]n ]sa
[run tests]sx
lqx
[ABC] lqx
[ABC] [DEF] lqx
[ABC] [DEF] [G] [H] lqx</syntaxhighlight>
{{out}}
<pre>{}
{ABC}
{ABC and DEF}
{ABC, DEF, G and H}</pre>
=={{header|DCL}}==
Line 1,390 ⟶ 1,542:
{ABC and DEF}
{ABC, DEF, G and H}</pre>
=={{header|Delphi}}==
See [[#Pascal|Pascal]].
Line 1,413 ⟶ 1,566:
"{ABC and DEF}"
"{ABC, DEF, G and H}"</pre>
=={{header|EasyLang}}==
<syntaxhighlight lang=text>
func$ tolist s$ .
s$[] = strsplit s$ " "
r$ = "{"
n = len s$[]
for i = 1 to n - 2
r$ &= s$[i] & ", "
.
if n > 0
if n > 1
r$ &= s$[n - 1] & " and "
.
r$ &= s$[n]
.
r$ &= "}"
return r$
.
print tolist ""
print tolist "ABC"
print tolist "ABC DEF"
print tolist "ABC DEF G H"
</syntaxhighlight>
=={{header|EchoLisp}}==
Line 1,437 ⟶ 1,614:
("ABC" "DEF" "G" "H") ----> "{ ABC, DEF, G and H }"
</syntaxhighlight>
=={{header|ed}}==
Uses basic regular expressions (BREs).
<syntaxhighlight lang="sed">
# by Artyom Bologov
H
,p
g/.*/s/ /, /g
g/[,]/s/,\([^,]*\)$/ and\1/
g/.*/s//{&}/
,p
Q
</syntaxhighlight>
{{out}}
<pre>$ ed -s comma-quibling.input < comma-quibling.ed
Newline appended
ABC
ABC DEF
ABC DEF G H
{}
{ABC}
{ABC and DEF}
{ABC, DEF, G and H}</pre>
=={{header|Eiffel}}==
Line 1,800 ⟶ 2,004:
{ABC, DEF, G and H}
</pre>
=={{header|Frink}}==
<syntaxhighlight lang="frink">quibble[enum] :=
Line 1,820 ⟶ 2,025:
{ABC and DEF}
{ABC, DEF, G and H}
</pre>
=={{header|FutureBasic}}==
Long solution:
<syntaxhighlight lang="futurebasic">
include "NSLog.incl"
local fn CommaQuibber( string as CFStringRef ) as CFStringRef
CFStringRef tempStr
NSUInteger i
tempStr = fn StringByReplacingOccurrencesOfString( string, @"[", @"" )
tempStr = fn StringByReplacingOccurrencesOfString( tempStr, @"]", @"" )
tempStr = fn StringByReplacingOccurrencesOfString( tempStr, @" ", @"" )
tempStr = fn StringByReplacingOccurrencesOfString( tempStr, @"\"", @"" )
CFMutableStringRef quibStr = fn MutableStringWithCapacity(0)
CFArrayRef arr = fn StringComponentsSeparatedByString( tempStr, @"," )
NSUInteger count = len(arr)
select switch ( count )
case 0 : MutableStringSetString( quibStr, @"{}" ) : break
case 1 : MutableStringSetString( quibStr, fn StringWithFormat( @"{%@}", arr[0] ) ) : break
case 2 : MutableStringSetString( quibStr, fn StringWithFormat( @"{%@ and %@}", arr[0], arr[1] ) ) : break
case else
MutableStringAppendFormat( quibStr, @"{" )
for i = 0 to count -1
if ( i != count -1 )
MutableStringAppendFormat( quibStr, @"%@, ", arr[i] )
else
MutableStringAppendFormat( quibStr, @"and %@}", arr[i] )
end if
next
end select
end fn = quibStr
NSLog( @"%@", fn CommaQuibber( @"[]" ) )
NSLog( @"%@", fn CommaQuibber( @"[\"ABC\"]" ) )
NSLog( @"%@", fn CommaQuibber( @"[\"ABC\", \"DEF\"]" ) )
NSLog( @"%@", fn CommaQuibber( @"[\"ABC\", \"DEF\", \"G\", \"H\"]" ) )
HandleEvents
</syntaxhighlight>
Short solution:
<syntaxhighlight lang="futurebasic">
local fn CommaQuibbler( s as CFArrayRef ) as CFStringRef
CFStringRef result = NULL
select ( len(s) )
case 0: exit fn = @"{}"
case 1: exit fn = fn StringWithFormat( @"{%@}", s[0] )
case 2: exit fn = fn StringWithFormat( @"{%@ and %@}", s[0], s[1] )
case else
result = fn StringWithFormat( @"{%@}", fn ArrayComponentsJoinedByString( s, @", " ) )
CFRange lastComma = fn StringRangeOfStringWithOptions( result, @",", NSBackwardsSearch )
result = fn StringByReplacingCharactersInRange( result, lastComma, @" and" )
end select
end fn = result
print fn CommaQuibbler( @[] )
print fn CommaQuibbler( @[@"ABC"] )
print fn CommaQuibbler( @[@"ABC", @"DEF"] )
print fn CommaQuibbler( @[@"ABC", @"DEF", @"G", @"H"] )
HandleEvents
</syntaxhighlight>
Shorter solution:
<syntaxhighlight lang="futurebasic">
local fn Quibble( string as CFStringRef ) as CFStringRef
CfArrayRef arr = fn StringComponentsSeparatedByString( string, @" " )
CFStringRef rst
if ( len(arr) == 0 ) then rst = @"" else rst = fn StringWithFormat( @"%@", fn ArrayLastObject( arr ) )
if ( len(arr) > 1 )
CFArrayRef subArray = fn ArraySubarrayWithRange( arr, fn CFRangeMake( 0, len(arr) - 1 ) )
rst = fn StringWithFormat( @"%@ and %@", fn ArrayComponentsJoinedByString( subArray, @", " ), rst )
end if
end fn = fn StringWithFormat( @"{%@}", rst )
print fn Quibble( @"" )
print fn Quibble( @"ABC")
print fn Quibble( @"ABC DEF" )
print fn Quibble( @"ABC DEF G H" )
HandleEvents
</syntaxhighlight>
{{output}}
<pre>
{}
{ABC}
{ABC and DEF}
{ABC, DEF, G, and H}
</pre>
Line 1,925 ⟶ 2,222:
Or, defining just two cases, and drawing more on standard libraries than on hand-crafted pattern-matching and recursion:
<syntaxhighlight lang="haskell">import Data.List (intercalate)
--------------------- COMMA QUIBBLING --------------------
quibble :: [String] -> String
quibble ws@(_ : _ : _) =
intercalate
( [intercalate ", " . reverse . tail, head]
)
quibble xs = concat xs
--------------------------- TEST -------------------------
main :: IO ()
main =
mapM_ (putStrLn . (`intercalate` ["{", "}"]) . quibble) $
[[], ["ABC"], ["ABC", "DEF"], ["ABC", "DEF", "G", "H"]]
<> ( words
<$> [ "One two three four",
"Me myself I",
"Jack Jill",
"Loner"
]
)</syntaxhighlight>
{{Out}}
<pre>{}
Line 1,951 ⟶ 2,257:
=={{header|Icon}} and {{header|Unicon}}==
The following works in both languages:
<syntaxhighlight lang="unicon">procedure main()
Line 2,284 ⟶ 2,589:
["ABC", "DEF"] -> {ABC and DEF}
["ABC", "DEF", "G", "H"] -> {ABC, DEF, G and H}
</pre>
=={{header|Lang}}==
<syntaxhighlight lang="lang">
fp.quibble = (&words) -> {
$len $= @&words
$output = \{\e
$i
repeat($[i], $len) {
$output += &words[$i] ||| ($i == -|$len?\e:($i == $len - 2?\sand\s:\,\s))
}
$output += \}\e
return $output
}
fn.println(fp.quibble(fn.arrayOf()))
fn.println(fp.quibble(fn.arrayOf(ABC)))
fn.println(fp.quibble(fn.arrayOf(ABC, DEF)))
fn.println(fp.quibble(fn.arrayOf(ABC, DEF, G, H)))
</syntaxhighlight>
{{out}}
<pre>
{}
{ABC}
{ABC and DEF}
{ABC, DEF, G and H}
</pre>
Line 2,570 ⟶ 2,906:
=={{header|MATLAB}} / {{header|Octave}}==
<syntaxhighlight lang="matlab">
function r = comma_quibbling(varargin)
Line 2,638 ⟶ 2,973:
"{ABC, DEF, G and H}"
</syntaxhighlight>
=={{header|Miranda}}==
<syntaxhighlight lang="miranda">main :: [sys_message]
main = [Stdout (show test ++ ": {" ++ quibble test ++ "}\n") | test <- tests]
tests :: [[[char]]]
tests = [ [],
["ABC"],
["ABC","DEF"],
["ABC","DEF","G","H"] ]
quibble :: [[char]]->[char]
quibble [] = []
quibble [word] = word
quibble [word1,word2] = word1 ++ " and " ++ word2
quibble (word:words) = word ++ ", " ++ quibble words</syntaxhighlight>
{{out}}
<pre>[]: {}
["ABC"]: {ABC}
["ABC","DEF"]: {ABC and DEF}
["ABC","DEF","G","H"]: {ABC, DEF, G and H}</pre>
=={{header|NetRexx}}==
Line 2,685 ⟶ 3,041:
for i in s:
echo commaQuibble(i)</syntaxhighlight>
=={{header|Nu}}==
<syntaxhighlight lang="nu">def quibble [] {
if ($in | length) < 3 { $in } else [($in | drop | str join ', ') ($in | last)]
| $'{($in | str join " and ")}'
}
# test
[
[]
[ABC]
[ABC DEF]
[ABC DEF G H]
]
| each { quibble }</syntaxhighlight>
{{out}}
<pre>
╭───┬─────────────────────╮
│ 0 │ {} │
│ 1 │ {ABC} │
│ 2 │ {ABC and DEF} │
│ 3 │ {ABC, DEF, G and H} │
╰───┴─────────────────────╯
</pre>
=={{header|Oberon-2}}==
Line 2,750 ⟶ 3,130:
=={{header|Objeck}}==
<syntaxhighlight lang="objeck">class Quibbler {
function : Quibble(words : String[]) ~ String {
Line 2,793 ⟶ 3,172:
=={{header|OCaml}}==
<syntaxhighlight lang="ocaml">open Printf
Line 2,838 ⟶ 3,216:
=={{header|Oforth}}==
<syntaxhighlight lang="oforth">: quibbing(l) -- string
| i s |
Line 2,887 ⟶ 3,264:
=={{header|PARI/GP}}==
<syntaxhighlight lang="parigp">comma(v)={
if(#v==0, return("{}"));
Line 2,906 ⟶ 3,282:
=={{header|Pascal}}==
<syntaxhighlight lang="pascal">
program CommaQuibbling;
Line 3,056 ⟶ 3,431:
=={{header|Perl}}==
{{trans|Raku}}
<syntaxhighlight lang="perl">sub comma_quibbling :prototype(@) {
return "{$_}" for
@_ < 2 ? "@_" :
Line 3,073 ⟶ 3,448:
<syntaxhighlight lang="perl">use 5.01;
sub comma_quibbling {
my $last = pop // '';
return '{'. (@_ ? (join ', ', @_).' and '.$last : $last).'}';
Line 3,113 ⟶ 3,488:
=={{header|PHP}}==
<syntaxhighlight lang="php"><?php
function quibble($arr) {
case 0:
return '{}';
case 1:
return "{{$arr[0]}}";
default:
$right = array_slice($arr, -1)[0];
return "{{$left} and {$right}}";
}
}
Line 3,142 ⟶ 3,519:
foreach ($tests as $test) {
echo quibble($test) . PHP_EOL;
}
?></syntaxhighlight>
{{out}}
<pre>{}
Line 3,434 ⟶ 3,812:
=={{header|Prolog}}==
{{works with|SWI-Prolog|7.1}}
Line 3,722 ⟶ 4,099:
{ABC and DEF}
{ABC, DEF, G, and H}</pre>
=={{header|Refal}}==
<syntaxhighlight lang="refal">$ENTRY Go {
= <Prout <Quibble>>
<Prout <Quibble ('ABC')>>
<Prout <Quibble ('ABC') ('DEF')>>
<Prout <Quibble ('ABC') ('DEF') ('G') ('H')>>;
};
Quibble {
e.X = '{' <Quibble1 e.X> '}';
};
Quibble1 {
= ;
(e.Word) = e.Word;
(e.Word1) (e.Word2) = e.Word1 ' and ' e.Word2;
(e.Word) e.Words = e.Word ', ' <Quibble1 e.Words>;
};</syntaxhighlight>
{{out}}
<pre>{}
{ABC}
{ABC and DEF}
{ABC, DEF, G and H}</pre>
=={{header|REXX}}==
Line 3,860 ⟶ 4,261:
{ABC DEF}
{ABC, DEF, G and H}
</pre>
=={{header|RPL}}==
Whilst it is always important to ensure overall code clarity for maintenance by using explicit variable names and structured control flows, the spirit of reverse Polish notation programming is to optimize some key part of the algorithm in order to make it as compact - and possibly as fast - as possible, whatever the induced loss of readability. Here, two <code>IFTE</code> low-level instructions are nested to deliver the appropriate liaison substring between two words or before the first word.
{{works with|Halcyon Calc|4.2.7}}
≪ DUP SIZE → words n
≪ "{" 1
'''WHILE''' DUP n ≤ '''REPEAT'''
DUP 1 ≠ OVER n ≠ ", " " and " '''IFTE''' "" '''IFTE'''
ROT SWAP +
words 3 PICK GET +
SWAP 1 +
'''END'''
DROP "}" +
≫ ≫ 'CMAQBL' STO
{{in}}
<pre>
{ } CMAQBL
{ "ABC" } CMAQBL
{ "ABC", "DEF" } CMAQBL
{ "ABC", "DEF", "G", "H" } CMAQBL
</pre>
{{out}}
<pre>
4: "{}"
3: "{ABC}"
2: "{ABC and DEF}"
1: "{ABC, DEF, G and H}"
</pre>
Line 3,953 ⟶ 4,382:
=={{header|Scheme}}==
<syntaxhighlight lang="scheme">
(define (quibble . args)
Line 4,053 ⟶ 4,481:
{ABC, DEF, G and H}
</pre>
=={{header|SETL}}==
<syntaxhighlight lang="setl">program comma_quibbling;
tests := [
[],
["ABC"],
["ABC","DEF"],
["ABC","DEF","G","H"]
];
loop for t in tests do
print(t, "=", quibble(t));
end loop;
proc quibble(words);
ret := '{';
loop while words /= [] do
word fromb words;
ret +:= word;
case of
(#words = 1):
ret +:= " and ";
(#words > 1):
ret +:= ", ";
end case;
end loop;
return ret + '}';
end proc;
end program;</syntaxhighlight>
{{out}}
<pre>[] = {}
[ABC] = {ABC}
[ABC DEF] = {ABC and DEF}
[ABC DEF G H] = {ABC, DEF, G and H}</pre>
=={{header|Sidef}}==
<syntaxhighlight lang="ruby">func comma_quibbling(words) {
'{' + ([words.
}
[<>, <ABC>, <ABC DEF>, <ABC DEF G H>].each { |w|
say comma_quibbling(w)
}</syntaxhighlight>
{{out}}
Line 4,132 ⟶ 4,595:
=={{header|TXR}}==
<syntaxhighlight lang="txrlisp">(defun quib (list)
(tree-bind (: last . lead) (reverse list)
`{@{(nreverse lead) ", "}@(if lead " and ")@last}`))</syntaxhighlight>
=={{header|Uiua}}==
{{works with|Uiua|0.10.0-dev.1}}
<syntaxhighlight lang="Uiua">
Tests ← {{}
{"ABC"}
{"ABC" "DEF"}
{"ABC" "DEF" "G" "H"}}
Jam ← ◇⊂◇⊂:□
Quibble ← |1 ⟨""◌|°□⊢|Jam" and "°⊟|Quibble⊂⊃(□Jam", "°⊟↙2)(↘2)⟩↧3⧻.
Wrap ← ⊂⊂"{" : "}" Quibble
⍚(&pWrap) Tests
</syntaxhighlight>
=={{header|UNIX Shell}}==
{{works with|Bourne Again SHell}}
{{works with|Korn Shell}}
{{works with|Z Shell}}
<syntaxhighlight lang="bash">
quibble() {
printf '{'
shift
done
if (( $# )); then
printf '%s' "$1"
shift
fi
if (( $# )); then
printf ' and %s' "$1"
fi
printf '%s\n' '}'
}</syntaxhighlight>
With a slight modification, it will work in any POSIX shell, or even older Bourne-compatible shells as long as they have functions and <b>printf</b>:
<syntaxhighlight lang="sh">
quibble() {
printf '{'
while [ $# -gt 2 ]; do
printf '%s, ' "$1"
shift
done
if [ $# -gt 0 ]; then
printf '%s' "$1"
shift
fi
if [ $# -gt 0 ]; then
printf ' and %s' "$1"
fi
printf '%s\n' '}'
}</syntaxhighlight>
Going the other way, Zsh-specific code can be more compact:
{{works with|Z Shell}}
<syntaxhighlight lang="zsh">quibble() {
printf '{'
if (( $# > 1 )) printf '%s and ' ${(j:, :)@[1,-2]}
printf '%s}\n' $@[-1]
}</syntaxhighlight>
The test code is the same either way:
<syntaxhighlight lang="sh">
quibble
quibble ABC
Line 4,219 ⟶ 4,734:
=={{header|Visual Basic .NET}}==
FormatEnumerable() accepts an IEnumerable(Of String), as per Lippert's original specification. FormatArray() contains an alternative implementation for String().
Line 4,275 ⟶ 4,789:
{ABC, DEF, G and H}</pre>
=={{header|V (Vlang)}}==
{{trans|go}}
<syntaxhighlight lang="v (vlang)">fn q(s []string) string {
match s.len {
0 {
Line 4,309 ⟶ 4,823:
=={{header|Wren}}==
<syntaxhighlight lang="
var c = w.count
if (c == 0) return "{}"
|