| Bytes | Lang | Time | Link |
|---|---|---|---|
| 031 | Vyxal ṡ | 211125T055115Z | emanresu |
| 076 | Uiua | 240130T153047Z | Joao-3 |
| 061 | Perl 5 + pl | 211125T100847Z | Dom Hast |
| 147 | TypeScript's type system | 240127T001605Z | noodle p |
| 116 | Julia | 220215T223423Z | David Sc |
| 082 | Julia 1.0 | 211125T093623Z | MarcMush |
| 077 | BQN | 211221T180947Z | DLosc |
| 129 | Python 3 | 211203T154432Z | Alan Bag |
| 136 | Rust | 211125T055608Z | bigyihsu |
| 095 | Python3 | 211126T215845Z | Ajax1234 |
| nan | Prolog | 211129T135259Z | Esteis |
| 126 | SimpleTemplate 0.84 | 211128T055953Z | Ismael M |
| 170 | Batch | 211127T235742Z | Neil |
| 067 | Zsh | 211125T092155Z | pxeger |
| 077 | Whython | 211125T100044Z | pxeger |
| 136 | Python 3 | 211125T011315Z | Fmbalbue |
| 107 | C clang m32 | 211125T033156Z | a stone |
| 144 | C clang with m32 | 211125T044105Z | ErikF |
| 073 | Ruby | 211125T080736Z | G B |
| 091 | PHP | 211125T161118Z | Kaddath |
| 093 | Java | 211126T031330Z | Unmitiga |
| 086 | APL+WIN | 211125T212422Z | Graham |
| nan | jq | 211125T105805Z | cnamejj |
| 099 | Lua | 211125T180353Z | Henrik I |
| 102 | Python 2 | 211125T170242Z | ElPedro |
| 100 | Excel | 211125T132823Z | Wernisch |
| 101 | Dart | 211125T130203Z | Ben Broo |
| 089 | Pari/GP | 211125T122937Z | alephalp |
| 048 | Charcoal | 211125T095923Z | Neil |
| 063 | Retina 0.8.2 | 211125T094521Z | Neil |
| 094 | Haskell | 211125T093457Z | ovs |
| 042 | 05AB1E | 211125T092432Z | Kevin Cr |
| 102 | R | 211125T074001Z | pajonk |
| 089 | Vim | 211125T060337Z | DLosc |
| 052 | Pip | 211125T044205Z | DLosc |
| 089 | Python 3 | 211125T013109Z | hyperneu |
| 047 | Jelly | 211125T013442Z | caird co |
| 041 | Vyxal ṡ | 211125T012543Z | lyxal |
| 082 | JavaScript | 211125T013414Z | Youserna |
| 077 | JavaScript | 211125T014459Z | tsh |
Vyxal ṡ, 31 bytes
ḣ[‛λ¬?Ḣḣ[_?L‹‛÷„]‛λ½|‛is]`Ȯ»...
ḣ # Push the first item (first user) and the rest to the stack
# The first item will remain on the bottom of the stack
[ ] # If the rest exists (More than one user)
‛λ¬ # Push 'and'
?Ḣ # Take all users but the first
ḣ # Push the first item (second user) and rest to the stack
[ ] # If the rest exists (≥3 users)
_ # Pop the second user
?L‹ # Push the input's length, -1
‛÷„ # Push 'others'
‛λ½ # Push 'are'
| # Otherwise (one user)
‛is # Pop the resulting empty list and push 'is'
`Ȯ»... # Push 'typing...'
# (ṡ flag) join stack by spaces)
34 bytes flagless.
Uiua, 76 bytes
$"_ typing..."($"_ is"⊔⊢|/$"_ and _ are"|$"_ and _ others are":-1⊃⧻⊢)+1±-2⧻.
Perl 5 + -pl, 61 bytes
Thanks to @Xcali for -2!
s;$; @{[!(@_=<>)?is:'and',$#_?@_.' others':@_,are]} typing...
Explanation
The first name is implicitly stored in $_ (via -p) so it's easy to just add to it a string consisting of a leading space and an in-line list @{[...]}, finishing with typing... as that's always needed no matter what. The in-line list will be implicitly joined by $" (space), which allows use of some barewords, saving bytes for the quotes. The rest of the input (<>) is slurped into @_ which, if it's non-empty, results in a list consisting of 'and', and if $#_ is truthy ($#_ is the last array index of @_, which will be 0 if there is only one entry), we use @_ in a scalar context (which is the number of elements i n@_) concatenated with ' others', but if @_ only contains one entry, add it as is. If @_ is empty, we just add the bareword is to the in-line list.
TypeScript's type system, 147 bytes
//@ts-ignore
type F<A,B=A extends[{},...infer B]?B["length"]:0>=`${A[0]} ${B extends 0?"is":`and ${B extends 1?A[1]:`${B} others`} are`} typing...`
Julia, 116 bytes
f(l,s=length(l))=replace("x z typing...","x"=>l[1],"z"=>"$(s>1 ? "and $(s>2 ? "$(s-1) others" : l[2]) are" : "is")")
Note that this code does not work with Julia 1.0, thus I can not put it on Try it online. My test code in Julia 1.7 is as follows.
f(l,s=length(l))=replace("x z typing...","x"=>l[1],"z"=>"$(s>1 ? "and $(s>2 ? "$(s-1) others" : l[2]) are" : "is")")
a=["Bubbler"]
b=["no one"]
c=["HyperNeutrino", "user"]
d=["emanresu A", "lyxal", "Jo King"]
e=["pxeger", "null", "null", "null", "null", "null", "null", "null", "null", "null", "null"]
g=["10", "null", "null", "null", "null", "null", "null", "null", "null", "null", "null"]
h=["and", "are"]
k=["is"]
l=["Bubbler is typing", "is", "are", "and"]
println(f(a))
println(f(b))
println(f(c))
println(f(d))
println(f(e))
println(f(g))
println(f(h))
println(f(k))
println(f(l))
which produces the following output
Bubbler is typing...
no one is typing...
HyperNeutrino and user are typing...
emanresu A and 2 others are typing...
pxeger and 10 others are typing...
10 and 10 others are typing...
and and are are typing...
is is typing...
Bubbler is typing and 3 others are typing...
Maybe I can ask the developers of Try it online! to upgrade the Julia version.
Julia 1.0, 82 bytes
t=" typing..."
>(x)="$x is$t"
x>y="$x and $y are$t"
x>y...=x>"$(length(y)) others"
the names are expected as arguments of the function >, for example >("Bubbler"), >("a","b","c")
Julia 0.7, 79 75 bytes
!t=t[(L=end-1;1)]*" $(L<1?:is:"and $(L<2?t[2]:"$L others") are") typing..."
BQN, 77 bytes
⊑∾" typing..."∾˜·(0<≠)◶⟨" is"⋄" and "∾" are"∾˜(1<≠)◶⟨⊑⋄" others"∾˜•fmt∘≠⟩⟩1⊸↓
Anonymous tacit function that takes a list of strings and returns a string. Run it online!
Explanation
(0<≠)◶⟨" is"⋄...⟩1⊸↓
1⊸↓ Drop the first element of the argument list
( )◶ Choose, based on the result of this function:
≠ Length of the remaining list
0< is greater than 0? (1 if so, 0 if not)
⟨ ⟩ one of these functions:
" is" Return that string
⋄ or...
" and "∾" are"∾˜(1<≠)◶⟨⊑⋄...⟩
( )◶ Choose, based on the result of this function:
≠ Length of the all-but-the first list
1< is greater than 1?
⟨ ⟩ one of these functions:
⊑ First element of the all-but-the-first list
⋄ or... (see below)
" are"∾˜ Append that string to the result
" and "∾ Prepend that string to the result
" others"∾˜•fmt∘≠
≠ Length of the all-but-the-first list
•fmt∘ Format as string
" others"∾˜ Append that string to the result
⊑∾" typing..."∾˜·...
... Calculate all of the above
· and then
" typing..."∾˜ Append that string to the result
⊑∾ Prepend the first element of the argument list
Python 3, 129 bytes
lambda u:(f"{(u[0])} is"if len(u)<2else f"{u[0]} and {u[1]} are"if len(u)<3else f"{u[0]} and {len(u)-1} others are")+" typing..."
A different approach that was much harder to write is 155 bytes :(
Python 3, 155 bytes
lambda u:f"{u[0]} %s%s%s typing..."%(["and ",""][len(u)<2],""if len(u)<2else u[1]if len(u)<3else len(u)-1,[" are","is"][len(u)<2]+[""," others"][len(u)>2])
Rust, 185 183 162 136 bytes
|v:&[&str]|[v[0],&match v.len(){1=>"is".into(),2=>format!("and {} are",v[1]),l=>format!("and {} others are",l-1)},"typing..."].join(" ")
Ungolfed:
|v: &[&str]| {
[
v[0],
&match v.len() {
1 => "is".into(),
2 => format!("and {} are", v[1]),
l => format!("and {} others are", l - 1),
},
"typing...",
]
.join(" ")
}
Log:
- -2 for excluding the closure name
- -21 for
v:&[&str], implicit return type, wildcard with binding,sremoval, brackets. Thanks @AnttiP! - -26 for removing redundant
"typing..."occurrences and oneformat!use (by @Ezhik)
Python3, 95 bytes:
lambda d:f'{d[0]} {"and "+[d[1],f"{l-1} others"][l>2]+" are"if(l:=len(d))>1else"is"} typing...'
This solution requires no pre-formatting of the input list (i.e no unpacking).
Prolog, 108 135 bytes (of which 27 are spent on producing a string)
This was fun, although Prolog does not have very much scope for golfery. My first, unsubmitted, attempt tried to use Prolog's Directed Clause Grammar syntax, but I couldn't get that to be shorter.
IIRC the rules here on CoGoSO correctly, it is permitted to return a string, and not required to print it; so I'm returning in a variable (O), as is traditional in Prolog.
f([X|R],O):-g(R,P),flatten([X,P,typing],Q),atomics_to_string(Q,' ',O).
g([],is).
g(L,[and,C,are]):-L=[Y],C=Y;C=[N,others],length(L,N).
Legend to the one-letter variable names:
% X: first name
% R: Rest of the names
% L: Rest of the names, seen from g/2's perspective
% O: Output
% C: Company, i.e. a word list like '[and, Y]'.
% P: intermediate output: nested list of atoms (representing inner words)
% Q: intermediate result: flat list of atoms
Usage examples:
?- f([jan,piet,klaas,tjoris,korneel], O).
O = "jan and 4 others are typing"
?- f([jan,piet,klaas], O).
O = "jan and 2 others are typing"
?- f([jan,piet], O).
O = "jan and piet are typing"
?- f([jan], O).
O = "jan is typing"
Ungolfed:
f([X|MoreNames], Out) :-
% InnerWords like 'is' or '[and, Y, are]'
innerwords(MoreNames, InnerWords),
% Flatten `[X, [and, [N others], are], typing]`
% to `[X, and, N, others, are, typing]`
flatten([X, InnerWords, typing], AllWords),
% Turn it into a string. This is not a very Prolog thing to
% do, but the challeng requests it, so here goes.
atomics_to_string(AllWords, ' ', Out).
% No more others: produce 'is' for 'X is typing'.
innerwords([], is).
% One or more others
innerwords(MoreNames, [and, Company, are]) :-
% MoreNames is a list of 1, s
Company=Y, MoreNames=[Y] ;
% If we reach here, there are 2+ others.
% (Or our caller is wrongly asking for additional solutions,
% and getting wrong answers as a reward.)
% [and, [N, others], are]
Company=[N, others], length(MoreNames, N).
SimpleTemplate 0.84, 126 bytes
This full program expects a variable number of arguments passed to the render() method. Argument unpacking can be used for convenience. Each argument is 1 user.
{@echoargv.0}{@ifargc is1} is{@else} and {@ifargc is2}{@echoargv.1}{@else}{@set-T argc,1}{@echoT} others{@/} are{@/} typing...
This will output the text into the standard output, by default.
Ungolfed:
To make it easier to understand, here's an ungolfed version of the code above:
{@echo argv.0}
{@if argc is 1}
{@echo " is"}
{@else}
{@echo " and "}
{@if argc is 2}
{@echo argv.1}
{@else}
{@set- count argc, 1}
{@echo count, " others"}
{@/}
{@echo " are"}
{@/}
{@echo " typing..."}
About the language:
There are a few important things to keep in mind when reading the code.
This section is important, but code is importanter.
All text that isn't part of an instruction, is just displayed as-is.
Newlines and all, except when what is to be displayed is just whitespace, which will be deleted by default.
The variables
argvandargcalmost the same as the$argvand$argcvariables in PHP, orargvandargcin C.However, the first argument in
argvis the first argument passed to therender()method of the compiler, instead of the name of the file.Whitespace handling is super loose, so,
{@echo 123}and{@echo123}work the same. This helps saving a lot of space.The line
{@echo argv.0}shows the syntax to access an array element.
This line is accessing the 1st 0-indexed element in the arrayargv.The line
{@set- count argc, 1}looks weird.
All it does is to set the the variablecountto the value ofargc - 1.The
set-(set minus) instruction does both operations in one.
This is the same as{@set count argc}{@inc by -1 count}, or$argc = $count; $count += -1;, but all in 1.The lines
{@if argc is <val>}are verifying isargcis<value>(1 or 2, in this case).
Internally, this will verify ifargcand<value>are identical, with the === operator.
Running the code:
You can run the code on: http://sandbox.onlinephpfunctions.com/code/7233b0a3b8b2fd96924e054944e4ddc850c8f381
Please pick a version between 5.6 and 7.4.13. Can't fix the 8.0.0 compatibility issue without invalidating this answer.
Batch, 170 bytes
@if "%2"=="" echo %~1 is typing...&exit/b
@set s=%~1
@set t=%~2
@set n=2
:l
@if not "%3"=="" set t=%n% others&set/an+=1&shift&goto l
@echo %s% and %t% are typing...
Takes input as command-line parameters. Explanation:
@if "%2"=="" echo %~1 is typing...&exit/b
Handle the case of there only being one user.
@set s=%~1
@set t=%~2
@set n=2
Assume there are two users.
:l
@if not "%3"=="" set t=%n% others&set/an+=1&shift&goto l
While more users are found, update the number of others and increment the total number of users.
@echo %s% and %t% are typing...
Output the users or count as appropriate.
Zsh, 67 bytes
x=(is "and $2 are")
echo $1 ${x[#]-and $[~-#] others are} typing...
Looks up the correct format string into the array $x (one of is, and $2 are, or an unset variable), defaulting to and $[~-#] others are (where $[~-#] is number of arguments - 1), and prints that with the first input $1 and the string typing....
Zsh, 79 bytes
T=\ typing... 1()<<<$1\ is$T 2()<<<"$1 and $2 are$T" $# $@||2 $1 $[~-#]\ others
- Defines two functions called
1and2which print formatted messages for singular and plural, respectively - Then it calls the function with the name
$#(the number of arguments), so that if 1 or 2 people are typing, the correct message is printed - If there are more than 2 arguments, the function call will fail, triggering the
||branch- This calls
2with the first argument and the string$[~-#] others- (It has to be
~-#, because#-1doesn't work, although I don't really understand why)
- (It has to be
- This calls
Whython, 84 77 bytes
f=lambda a,*b:a+f" {'and %s are'%b?'is'%b} typing..."?f(a,f"{len(b)} others")
This is my first answer in Whython, a horrible modification of Python I made. Its only new feature so far is ?, which is a short-circuiting exception [mis-]handling operator.
Here I use it to handle the case where there are more than 2 people typing: I recurse on the function f with a newly formatted second argument.
This answer also makes use of the (not Whython-specific) fact that you can %-format a string with a tuple of arguments, as long as it's the right number of arguments - and that number can also be 0 or 1 - so both " is"%() and " and %s are"%("second argument",) work fine.
-7 bytes thanks to @ovs: by trying to format and %s are (which requires b to be of length 1), then trying to format is (which requires b to be empty), we can save some bytes by avoiding len().
Python 3, 161 136 bytes
x=input().split(",")
y=len(x)
if y==1:z="is",
if y==2:z="and",x[1],"are"
if y>2:z="and",len(x)-1,"others are"
print(x[0],*z,"typing...")
I FGITW faster.
C (clang) -m32, 109 107 bytes
-2 thanks to ErikF!
t(*n,l){printf(--l?l-1?"%s and %d others are%s":"%s and %s are%s":"%s is%3$s",*n,l-1?l:n[1]," typing...");}
Try it online! Takes input as an array of char* and its length.
C (clang), 115 108 bytes
-7 thanks to ErikF!
t(**n,l){printf(--l?l-1?"%s and %d others are%s":"%s and %s are%s":"%s is%3$s",*n,l-1?l:n[1]," typing...");}
Try it online! Takes input as an array of char* and its length.
C (clang) with -m32, 151 148 144 bytes
- -3 thanks to ceilingcat
- -4 by changing the base index from 0 to -1
To try a different approach from the other C submission, only the list of strings is needed as input for this answer. To get the length of the list, the function is called recursively and output is printed as the function processes the list.
De-golfed:
g(*s,i) { // type-punning 'char **' as 'int *'
printf(
~i? // is this the first element?
*s? // (first element) no: end of list?
i? // (end of list) no: is this the second element?
"": // (second element) no, don't print if there is only 1 element
s[1]? // (second element) yes, are there only 2 elements?
"": // no, don't print second element if there are more than 2
" and %s": // yes, print second element
i<2? // (end of list) yes: are there more than 2 elements?
"": // no
" and %d others": // yes, print summary
*s, // (first element) yes: print first element
*s?
: // use string if not at end
i); // otherwise use the list count
*s?
g(s+1,i+1): // continue processing list
printf(" %s typing...", i<2? "is": "are");
}
f(s) { g(s,-1); } // initialize list count
g(*s,i){printf(~i?*s?i?"":s[1]?"":" and %s":i<2?"":" and %d others":*s,*s?:i);*s?g(s+1,i+1):printf(" %s typing...",i?"are":"is");}f(s){g(s,-1);}
Ruby, 79 ... 73 bytes
->a,*s{[a,s[0]?[:and,s[1]?[s.size,:others]:s,:are]:"is","typing..."]*" "}
Thanks ovs for -3 bytes
PHP, 94 91 bytes
fn($a)=>"$a[0] ".($a[1]?'and '.($a[2]?count($a)-1 .' others':$a[1]).' are':is).' typing...'
Raw first try at it, probably still golfable. It's a pity PHP cannot handle concatenation or nested ternary conditions without brackets..
EDIT: 3 bytes saved with thanks to Dom Hastings and 640KB's suggestions!
Java, 93 bytes
a->a[0]+(a.length>1?" and "+(a.length>2?a.length-1+" others":a[1])+" are":" is")+" typing..."
APL+WIN, 86 bytes
Prompts for the user list as a nested vector
(,(8⍴2)⊤175+18 4 0[3⌊⍴u])/u[1],('is' 'and'),(⊂↑1↓u),(⊂¯1+⍴u←⎕),'others' 'are' 'typing'
jq, 99 99+1 (-r flag penalty) = 100 bytes
(length-1)as$l|.[0]as$n|["is","and \(.[1]) are"]|"\($n) \(.[$l]//"and \($l) others are") typing..."
I'm pretty sure there's room to golf this more, but not tonight. :)
Stash the length of the input list in
$l. stash the first element in `$n(length-1)as$l|.[0]as$nGenerate a new list consisting of two elements,
isandis 2nd-input-list-entry are|["is","and \(.[1]) are"]Print the first input list name, then index the list from step 2 by the number of entries in the input minus 1. The
//code is called if the index doesn't exist. In that case the alternate textand length-of-input-minus-1 areis used. Thetyping...string is appended regardless of what other choices were made.|"\($n) \(.[$l]//"and \($l) others are") typing..."
Lua, 110 108 99 bytes
a,b,c=...print((b and a.." and "..(c and(#{...}-1 .." others")or b).." are"or a.." is").." typing")
Takes input from command-line arguments, prints to stdout.
Python 2, 102 bytes
i=input()
l=len(i)
print(i[0]+" and "+[`l-1`+" others",i[-1]][l<3]+" are",i[0]+" is")[l<2],"typing..."
Simple nested list slices but takes advantage of no brackets required for printing in Python 2 and also the use of back ticks for the string conversion.
Excel, 100 bytes
=A1&IF(COUNTA(A:A)=1," is"," and "&(IF(COUNTA(A:A)=2,A2,COUNTA(A:A)-1&" others"))&" are")&" typing…"
Dart, 101 Bytes
f(a)=>a[0]+(a.length>1?" and ${a.length>2?"${a.length-1} others":"${a[1]}"} are" : " is")+" typing.";
Pari/GP, 89 bytes
a->Str(a[1]if(#a<2," is",Str(" and "if(#a<3,a[2],Str(#a-1" others"))" are"))" typing...")
Charcoal, 48 bytes
S WS⊞υι¿υ«and ¿⊖Lυ⁺Lυ others⊟υ are»is¦ typing...
Try it online! Link is to verbose version of code. Takes input as a list of newline-terminated strings, which for some reason is golfier than taking input as a JSON list. Explanation:
S
Output the first name and a space.
WS⊞υι
Read in any other names.
¿υ«
If there were any, then:
and
Output and (with a trailing space).
¿⊖Lυ
If there was more than one other, then...
⁺Lυ others
... concatenate the count to the string others (with a leading space) and output that, otherwise...
⊟υ
... output the last (and only other) name.
are
Output are (with a leading space).
»is
Otherwise, output is.
typing...
Output typing... (with a leading space).
Retina 0.8.2, 63 bytes
^.*$
$& is
(¶.*){2,}
¶$#1 others
¶(.*)
and $1 are
$
typing...
Try it online! Takes newline-delimited input but test suite splits on commas for convenience. Explanation:
^.*$
$& is
Just one person is typing.
(¶.*){2,}
¶$#1 others
If there are at least two others then replace the list with a single element giving their count.
¶(.*)
and $1 are
More than one person is typing.
$
typing...
Complete the sentence.
Haskell, 94 bytes
g(a:x)=a++f x++" typing..."
f[]=" is"
f[x]=" and "++x++" are"
f l=f[show(length l)++" others"]
05AB1E, 42 bytes
ćs©gĀi'€ƒ®ćsgĀi\Ig<'ˆ†]…is€™#Ig≠è“ÜÔ...“ðý
Try it online or verify all test cases.
Explanation:
ć # Extract head of the (implicit) input-list; pop and push
# remainder-list and first item separately
s # Swap so the remainder-list is at the top
© # Store it in variable `®` (without popping)
gĀi # Pop and if there are any strings left (2+ inputs):
'€ƒ '# Push dictionary string "and"
® # Push list `®`
ćs # Extract head and swap again
gĀi # Pop and if there are any strings left (3+ inputs):
\ # Discard the head we've pushed
Ig< # Push the input-length - 1
'ˆ† '# Push dictionary string "others"
] # Close both if-statements
…is€™ # Push dictionary string "is are"
# # Split it on spaces: ["is","are"]
Ig # Push the input-length
≠ # Check that it's NOT 1 (0 if 1; 1 otherwise)
è # Use that to index into the pair
“ÜÔ...“ # Push dictionary string "typing..."
ðý # Join the entire stack with space delimiter
# (after which the result is output implicitly)
See this 05AB1E tip of mine (section How to use the dictionary?) to understand why '€ƒ is "and"; 'ˆ† is "others"; …is€™ is "is are"; and “ÜÔ...“ is "typing...".
R, 113 102 bytes
Or R>=4.1, 95 bytes by replacing the word function with \.
function(s,l=length(s)-1,`?`=paste)s[1]?"if"(l,"and"?"if"(l-1,l?"others",s[2])?"are","is")?"typing..."
It appears that paste chains nicely, so we can rename that to ? and use like string addition (with convenient spaces).
Vim, 92 89 bytes
:3,$s/.*/\=line('.')-1.' others'
:1s/\v(\n.+)+/\1
:2s/^/and
ois typing...<esc>:3s/is/are
V{J
Explanation
:3,$s/.*/\=line('.')-1.' others'<cr>
On every line from line 3 to the end of the buffer (if they exist), replace the contents of the line with the line number minus 1 followed by the string others.
:1s/\v(\n.+)+/\1<cr>
Beginning at (the end of) line 1, find 1 or more matches of a newline followed by some characters. Replace with the last (newline + characters) match.
:2s/^/and <cr>
Add and at the beginning of line 2 (if it exists).
ois typing...<esc>
Open a new line after the cursor (which is always on the last line at the point) and insert is typing....
:3s/is/are
If that new line was line 3, change is to are (if it was line 2, leave unchanged).
V{J
Enter visual line mode, select to the beginning of the buffer, and join lines (space-separated).
Pip, 52 bytes
[POgg?["and"#c?[#g"others"]b"are"]"is""typing..."]Js
(Or 50 bytes in Pip -s, which would use a flag to accomplish the same thing as the Js at the end.)
Takes the names as separate command-line arguments. Try it online!
Explanation
One big list, with the exact contents depending on the number of inputs, joined on spaces:
[ ; List containing:
PO g ; Pop first element of g (the command-line args)
g ? ; Is g still nonempty?
[ ; If so (multiple names case), list containing:
"and" ; This string
# c ? ; Is the third cmdline arg nonempty?
[ ; If so (more than 2 names case), list containing:
# g ; Number of elements remaining in g
"others" ; and this string
]
b ; Otherwise (2 names case), second cmdline arg
"are" ; and this string
]
"is" ; Otherwise (single name case), this string
"typing..." ; and this string
]
J s ; Join that list (including all sublists) on space
Python 3, 89 bytes
lambda a,*b:a+f" {b and'and %s are'%[b[0],'%d others'%len(b)][len(b)>1]or'is'} typing..."
-2 bytes thanks to dingledooper
Jelly, 47 bytes
ḢɓL,“¥ṃkŒ»ƊḷḊ?“ and ”;;“@k»ʋ;“ is”$ḷ?ṭ⁹“Æʋ@1'ɼ»
Full program, as it uses Jelly's smash-printing and nilad dumping.
How it works
ḢɓL,“¥ṃkŒ»ƊḷḊ?“ and ”;;“@k»ʋ;“ is”$ḷ?ṭ⁹“Æʋ@1'ɼ» - Main link. Takes a list of usernames U on the left
Ḣ - Chop off the first username, B, and set U' to be U without its head
ɓ - Start a new dyadic link f(U', B)
? - If:
ḷ - U' is non-empty
ʋ - Then:
? - If:
Ḋ - U' has more than one element
Ɗ - Then:
L - Take the length of U'
“¥ṃkŒ» - Compressed string: " others"
, - Pair; [len(U'), " others"]
ḷ - Else: Yield B
“ and ”; - Prepend " and "
;“@k» - Append " are"
$ - Else:
;“ is” - Append " is"
ṭ⁹ - Tack all of this to the end of B
“Æʋ@1'ɼ» - Unparseable nilad. Smash print the previous stuff, then print " typing..."
Vyxal ṡ, 42 41 bytes
ḢḢ[₌hL‹` ÷„`+"]` λ¬ `j`is λ½`⌈?L‹ḃi`Ȯ»...
Lovely dictionary compression. 44 bytes flagless
Explained
ḢḢ[₌hL‹` ÷„`+"]` λ¬ `j`is λ½`⌈?L‹ḃi`Ȯ»...
ḢḢ # If the length of the input is > 2:
[₌hL‹ # Push the head of the input and the length of the input - 1
` ÷„`+ # and append the string " others" to that
" # and wrap both in a list
] # endif
` λ¬ `j # Join the top of the stack on " and "
`is λ½`⌈ # Push the list ["is", "are"]
?L‹ # And push the lenght of the input - 1
ḃi # boolify it to make it 0 or 1 (this is basically just checking if the list length is 1) and index into the list
`Ȯ»... # Push "typing..." to the stack
# The -ṡ flag joins the stack on spaces. Without it, you'd need `WṄ for +3 bytes.
JavaScript, 85 82 bytes
a=>(b=a.length,a[0]+(b<2?" is":` and ${b<3?a[1]:b-1+" others"} are`)+" typing...")
JavaScript, 77 bytes
a=>a[0]+` ${(l=a.length-1)?`and ${l>1?l+' others':a[1]} are`:'is'} typing...`