functionlikes($names){$namesCount=count($names);if($namesCount===0){return"no one likes this";}if($namesCount===1){returnsprintf("%s likes this",$names[0]);}if($namesCount===2){returnsprintf("%s and %s like this",$names[0],$names[1]);}if($namesCount===3){returnsprintf("%s, %s and %s like this",$names[0],$names[1],$names[2]);}if($namesCount>=4){$likesStringFormat="%s, %s and %d others like this";$otherNamesCount=$namesCount-2;returnsprintf($likesStringFormat,$names[0],$names[1],$otherNamesCount);}}
Coding since 11yo, that makes it over 30 years now ~~~
Have a PhD in Comp Sci ~~~
Love to go on bike tours ~~~
I try to stay as generalist as I can in this crazy wide place coding is at now.
This'd be a good use for template literals. Here's a quicky in javascript:
functionlikesStringForNames(names){const[first,second,third]=names;switch(names.length){case0:return"no one likes this";case1:return`${first} likes this`;case2:return`${first} and ${second} like this`;case3:return`${first}, ${second} and ${third} like this`;default:return`${first}, ${second} and ${names.length-2} others like this`;}}
Sanity check:
[[],["Peter"],["Jacob","Alex"],["Max","John","Mark"],["Alex","Jacob","Mark","Max"],["Alex","Mark",...Array(10000)]].map(likesStringForNames)-->["no one likes this","Peter likes this","Jacob and Alex like this","Max, John and Mark like this","Alex, Jacob and 2 others like this","Alex, Mark and 10000 others like this"]
I think you don't need the break after the return, it would be unreachable.
constlikes=(arr=[])=>{switch(arr.length){case0:return"no one likes this";case1:return`${arr[0]} likes this`;case2:return`${arr[0]} and ${arr[1]} like this`;case3:return`${arr[0]}, ${arr[1]} and ${arr[2]} like this`;default:return`${arr[0]}, ${arr[1]} and ${arr.length-2} others like this`;}}
letlikes=([a,b,...c])=>c.length>1?`${a}, ${b} and ${c.length} others like this`:c.length?`${a}, ${b} and ${c[0]} like this`:b?`${a} and ${b} like this`:a?`${a} likes this`:`no one likes this`;console.log(likes([]));// no one likes thisconsole.log(likes(["Peter"]));// Peter likes thisconsole.log(likes(["Jacob","Alex"]));// Jacob and Alex like thisconsole.log(likes(["Max","John","Mark"]));// Max, John and Mark like thisconsole.log(likes(["Alex","Jacob","Mark","Max"]));// Alex, Jacob and 2 others like this
functionwhoLike(names){constl=names.length;if(!l){return'No one likes this';}elseif(l===1){return`${names[0]} likes this.`;}elseif(l<4){return`${names.slice(0,l-1).join(', ')} and ${names[l-1]} like this.`;}return`${names.slice(0,2).join(', ')} and ${l-2} others like this.`;}
Strings in Rust are a bit tedious since you usually want to avoid extra allocations and there's ownership concerns, so this code has a lot more refs than I'd like, and the function signature is a classic, but otherwise I think it's kind of pretty.
What I like most is that there's no -2 for the length, because Rust pattern matching lets me capture the elements into another slice right there.
fnlike_text<S:AsRef<str>>(likes:&[S])->String{matchlikes{&[]=>"no one likes this".to_string(),&[refone]=>format!("{} likes this",one.as_ref()),&[refone,reftwo]=>format!("{} and {} like this",one.as_ref(),two.as_ref()),&[refone,reftwo,refthree]=>format!("{}, {} and {} like this",one.as_ref(),two.as_ref(),three.as_ref()),&[refone,reftwo,refrest@..]=>format!("{}, {} and {} others like this",one.as_ref(),two.as_ref(),rest.len())}}fnmain(){letlikes=["foo","bar","baz","quux"];println!("{}",like_text(&likes))}
Ruby string-formatting takes an array of arguments, so if my function takes an array of names, then I just need to feed it into some pre-formatted "templates". Also the use of splat-array which I don't completely understand actually.
def likes(names)
num_people = names.size
case num_people
when 0
"no one likes this"
when 1
"%s likes this" %names
when 2
"%s and %s like this" %names
when 3
"%s, %s and %s like this" %names
else
"%s, %s and %d others like this" %[*names[0..1], num_people - 2]
end
end
p likes [] # must be "no one likes this"
p likes ["Peter"] # must be "Peter likes this"
p likes ["Jacob", "Alex"] # must be "Jacob and Alex like this"
p likes ["Max", "John", "Mark"] # must be "Max, John and Mark like this"
p likes ["Alex", "Jacob", "Mark", "Max"] # must be "Alex, Jacob and 2 others like this"
defwho_likes_this(names:list)->str:who='no one'number_of_likes=len(names)ifnumber_of_likes>0andnumber_of_likes<3:who=' and '.join(names)elifnumber_of_likes>=3:who=', '.join(names[:2])who+=' and '+(names[2]ifnumber_of_likes==3elsef' and {len(names[2:])} others')returnf'{who} like{""ifnumber_of_likes>1else"s"} this'
fromtypingimportListdeflikes(names:List[str])->str:messages={0:'no one likes this',1:'%s likes this',2:'%s and %s like this',3:'%s, %s and %s like this'}message=messages.get(len(names))ifnotmessage:return'%s, %s and %d others like this'%(*names[:2],len(names)-2)returnmessage%tuple(names)
There's probably a much simpler way to solve it, but hey, I basically know how to do pattern matching and recursion, so there we go:
defmoduleLikedodefwho_likes(list)docount=Enum.count(list)_who_likes(list,count-2)|>_add_likes(count)|>IO.putsenddefp_add_likes(x,n)when(n<2),do:"#{x} likes this"defp_add_likes(x,_),do:"#{x} like this"defp_who_likes([],_),do:"no one"defp_who_likes([a|[]],_),do:adefp_who_likes([a,b|[]],_),do:"#{a} and #{b}"defp_who_likes([a,b,c|[]],_),do:"#{a}, #{b} and #{c}"defp_who_likes([a,b|_tail],count),do:"#{a}, #{b} and #{count} others"end
constlikes=([a,b,c,...xs]:string[]):string=>a===undefined?"No one likes this.":b===undefined?`${a} likes this.`:c===undefined?`${a} and ${b} like this.`:xs.length===0?`${a}, ${b} and ${c} like this.`:`${a}, ${b} and ${[c,...xs].length} others like this.`;
publicstaticclassFormat{publicstaticstringLikeText(string[]names)=>names.Lengthswitch{0=>"no one likes this",1=>$"{names[0]} likes this",2=>$"{names[0]} and {names[1}} like this",3=>$"{names[0]}, {names[1]}, and {names[2]} like this",_=>$"{names[0]}, {names[1]}, and {names.Length-2} others like this",};}
likes::[String]->Stringlikes[]="no one likes this"likes[name]=name<>" likes this"likesnames=showMultiplenames<>" like this"showMultiple::[String]->StringshowMultiplexs=casexsof[]->""[x]->x[x,x']->x<>" and "<>x'[x,x',x'']->x<>", "<>showMultiple[x',x''](x:x':rest)->x<>", "<>x'<>" and "<>(show$lengthrest)<>" others"
constlikes=(names)=>{constmap=newMap([[0,'no one likes this'],[1,'{name} likes this'],[2,'{name} and {name} like this'],[3,'{name}, {name} and {name} like this'],[4,'{name}, {name} and {n} others like this'],]);returnmap.get(names.length<4?names.length:4).replace(/{name}|{n}/g,(val)=>val==='{name}'?names.shift():names.length);};
Cool I did this one 3 years ago over at CodeWars, here is the answer I posted:
functionlikes(names){switch(names.length){case0:return`no one likes this`;break;case1:return`${names[0]} likes this`;break;case2:return`${names[0]} and ${names[1]} like this`;break;case3:return`${names[0]}, ${names[1]} and ${names[2]} like this`;break;default:return`${names[0]}, ${names[1]} and ${names.length-2} others like this`;}}
The exception would be if the more "complex" solution was more performant.
For verification, I ran a perf test on the two funcs, and the switch idiom won out. (see screenshot below).
If another idiom were to beat out the switch idiom, I would swap out the implementation for the fastest idiom that uses the least cycles.
Wrap it in a function, document it, and include a resource link to the performance notes, tests and reasoning of the chosen implementation.
We're a place where coders share, stay up-to-date and grow their careers.
Here is the code snippets with PHP:
This'd be a good use for template literals. Here's a quicky in javascript:
Sanity check:
I think you don't need the break after the return, it would be unreachable.
Wasn't this in a previous challenge? I recall building this in HTML+CSS...
I think so Alvaro, i've also done this in python...
this is the one: dev.to/thepracticaldev/daily-chall...
Here is my proposition in JS:
Strings in Rust are a bit tedious since you usually want to avoid extra allocations and there's ownership concerns, so this code has a lot more
refs than I'd like, and the function signature is a classic, but otherwise I think it's kind of pretty.What I like most is that there's no
-2for the length, because Rust pattern matching lets me capture the elements into another slice right there.Permalink to the Rust Playground: play.rust-lang.org/?version=stable...
Ruby string-formatting takes an array of arguments, so if my function takes an array of names, then I just need to feed it into some pre-formatted "templates". Also the use of splat-array which I don't completely understand actually.
The solution in PHP
For Python
Test it:
Here's my version :)
Elixir
There's probably a much simpler way to solve it, but hey, I basically know how to do pattern matching and recursion, so there we go:
TypeScript
C# switch expressions to the rescue!
Very declarative Haskell solution:
Cool I did this one 3 years ago over at CodeWars, here is the answer I posted:
Looking at it now,
breakis not needed, as return breaks out of the switch statement.Javascript one-liner.
The cutoff can be changed.
This is a case where the switch block is probably the simplest idiom with the least cognitive load.
Having to use Math.min, conditional Regex's, replace callbacks, and array shifts, would be unnecessary complexity.
Good work showing the variants to outline the pros and cons though.
The exception would be if the more "complex" solution was more performant.
For verification, I ran a perf test on the two funcs, and the switch idiom won out. (see screenshot below).
If another idiom were to beat out the switch idiom, I would swap out the implementation for the fastest idiom that uses the least cycles.
Wrap it in a function, document it, and include a resource link to the performance notes, tests and reasoning of the chosen implementation.