This is a "don't do this at home" type of solution. Will it work? Yes. Is is worth it? We can all agree that CSS is always worth it (:P), but in this case, it may end up with a ton of unnecessary HTML code.
The idea is to use a ul/ol to represent the list of people, and with counters keep track of the number of likes (aka people in the list). Then with pseudo-elements display the appropriate message or connector.
ul,ol{display:block;list-style:none;padding-left:0;clear:both;height:40px;line-height:40px;counter-reset:people-2;}li{display:inline-block;float:left;font-size:1rem;counter-increment:people;}/* empty list */ul:empty::before,ol:empty::before{content:"No one likes this post.";}/* one element only */li:first-child:last-child::after{content:" likes this post.";}/* separate all names by commas */li:not(:first-child)::before{content:", ";}/* the last name (or from the third one) will end the list */li:nth-child(n+3)::before,li:last-child:not(:first-child)::before{content:"\00a0 and ";}/* add message for multiple names */li:nth-child(n+3)::after,li:last-child::after{content:" like this post.";}/* from the 4th element forth, they must be hidden */li:nth-child(n+3):not(:last-child){font-size:0;}/* the last element in a list of 4 or more is special */li:nth-child(n+4):last-child::before{font-size:1rem;content:"\00a0 and "counter(people)" others like this post.";}li:nth-child(n+4):last-child{font-size:0;}li:nth-child(n+4):last-child::after{content:"";}
likes::[String]->Stringlikes[]="no one likes this"likes[a]=a++" likes this"likes[a,b]=a++" and "++b++" like this"likes[a,b,c]=a++", "++b++" and "++c++" like this"likes(a:b:xs)=a++", "++b++" and "++(show$lengthxs)++" others like this"
deflikes(ls)caselsin[]"no one likes this"in[a]format"%s likes this",ain[a,b]format"%s and %s like this",a,bin[a,b,c]format"%s, %s and %s like this",a,b,cin[a,b,*rest]format"%s, %s and %d others like this",a,b,rest.sizeendendplikes([])# => "no one likes this"plikes(["Peter"])# => "Peter likes this"plikes(["Jacob","Alex"])# => "Jacob and Alex like this"plikes(["Max","John","Mark"])# => "Max, John and Mark like this"plikes(["Alex","Jacob","Mark","Max"])# => "Alex, Jacob and 2 others like this"
git clone git@github.com:ruby/ruby.git
cd ruby
autoconf
./configure optflags="-O0" debugflags="-g3" --prefix="$HOME/.rbenv/versions/master"
make && make install
rbenv global master
JS, with each case defined. I went for straightforward, though there's probably room to condense this somehow given the repetition:
constlikes=names=>{switch(names.length){case0:return"no one likes this"case1:return`${names[0]} likes this`case2:return`${names[0]} and ${names[1]} like this`case3:return`${names[0]}, ${names[1]} and ${names[2]} like this`default:return`${names[0]}, ${names[1]} and ${names.length-2} others like this`}}
constlikeText=(likes=[])=>{if(!likes.length)return'no one likes this';const[first,second,third,...rest]=likesif(!second)return`${first} likes this`;if(!third)return`${first} and ${second} like this`;if(!rest.length)return`${first}, ${second} and ${third} like this`;return`${first}, ${second} and ${rest.length+1} others like this`;}
fnfb_likes(names:&[&str])->String{matchnames.len(){0=>"no one likes this".to_string(),1=>format!("{} likes this",names[0]),2=>format!("{} and {} like this",names[0],names[1]),3=>format!("{}, {} and {} like this",names[0],names[1],names[2]),_=>format!("{}, {} and {} others like this",names[0],names[1],names.len()-2),}}
f([])"no one likes this"f(["Peter"])"Peter likes this"f(["Jacob","Alex"])"Jacob and Alex like this"f(["Max","John","Mark"])"Max, John and Mark like this"f(["Alex","Jacob","Mark","Max"])"Alex, Jacob and 2 others like this"
Basically, with a bit of wibbly wobbly trickery, depending on the input length, we either call the format function with ["no one"], the complete input, or the two first elements followed by the remaining quantity of items. Finally, we add (or not) an s to the like, and return the built string!
functionlikes(people){switch(people.length){case0:return'no one likes this';case1:return`${people[0]} likes this`;case2:return`${people[0]} and ${people[1]} like this`;case3:return`${people[0]}, ${people[1]} and ${people[2]} like this`;default:return`${people[0]}, ${people[1]} and ${people.length-2} others like this`;}}
$likes=["Alex","John","Jeremiah","David","Travis"];$message="";switch($likes){case(!isset($likes)):$message="no one likes this";break;case(sizeof($likes)==1):$message="$likes[0] likes this";break;case(sizeof($likes)==2):$message="$likes[0] and $likes[1] like this";break;case(sizeof($likes)==3):$message="$likes[0], $likes[1] and $likes[2] like this";break;case(sizeof($likes)>3):$message="$likes[0], $likes[1] and ".(sizeof($likes)-2)." others like this";break;default:$message="no one likes this";}echo$message;
At first i've used a lot of if statement then i got excited and tried another point
Python version (using as fewer ifs as possible):
defshow_likes(persons:List[str])->str:messages={0:'no one likes this',1:'%s like this',2:'%s and %s like this',3:'%s, %s and %s like this',4:'%s, %s and %d others like this'}likes_quantity=len(persons)content=messages.get(likes_quantity)ormessages[4]iflikes_quantity>3:returncontent%(persons[0],persons[1],len(persons[2:]))returncontent%(tuple(persons))
fromcollectionsimportdefaultdictmessages=defaultdict(lambda:'%s, %s and %d others like this',{0:'no one likes this',1:'%s like this',2:'%s and %s like this',3:'%s, %s and %s like this',})likes_quantity=len(persons)content=messages[likes_quantity]
But of course - all of this is redundant, since you already check for likes_quantity > 3. So how about this:
defshow_likes(persons:List[str])->str:messages={0:'no one likes this',1:'%s like this',2:'%s and %s like this',3:'%s, %s and %s like this',}likes_quantity=len(persons)iflikes_quantity>3:return'%s, %s and %d others like this'%(persons[0],persons[1],len(persons[2:]))returnmessages[likes_quantity]%tuple(persons)
funvoidlikes(stringarray[]){array.size()=>constintsz;switch(sz){case0:<<<"no one"," likes this">>>;break;case1:<<<array[0]," likes this">>>;break;case2:<<<array[0]," and ",array[1]," like this">>>;break;case3:<<<array[0],", ",array[1]," and ",array[2]," like this">>>;break;default:<<<array[0],", ",array[1]," and ",sz-2," others"," like this">>>;break;}}["Peter"]=>likes;["Jacob","Alex"]=>likes;["Max","John","Mark"]=>likes;["Alex","Jacob","Mark","Max"]=>likes;
moduleMainexposing(main)importHtmlexposing(Html,p,text,div)likes:ListString->Stringlikesnames=casenamesof[]->"no one likes this"name::[]->name++" likes this"first::second::[]->first++" and "++second++" like this"first::second::third::[]->first++", "++second++" and "++third++" like this"first::second::rest->first++", "++second++" and "++(String.fromInt<|List.lengthrest)++" others like this"main:Htmlactionsmain=div[][p[][text<|likes[]]-- no one likes this,p[][text<|likes["Peter"]]-- Peter likes this,p[][text<|likes["Jacob","Alex"]]-- Jacob and Alex like this,p[][text<|likes["Max","John","Mark"]]-- Max, John and Mark like this,p[][text<|likes["Alex","Jacob","Mark","Max"]]-- Alex, Jacob and 2 others like this]
publicStringmessage(List<String>list){switch(list.toArray().length){case0:return"no one likes this";case1:returnlist.get(0)+" likes this";case2:returnlist.get(0)+" and "+list.get(1)+" like this";case3:returnlist.get(0)+", "+list.get(1)+" and "+list.get(2)+" like this";default:returnlist.get(0)+","+list.get(1)+" and "+(list.toArray().length-2)+" other like this";}
Perl solution. The special array @_ contains the arguments of a subroutine, but in scalar context it returns the number of them.
#!/usr/bin/perlusewarnings;usestrict;usefeatureqw{ say };sub likes{my$count=@_-2;sprintf((('no one','%s','%s and %s','%s, %s, and %s',)[scalar@_]||"%s, %s, and $count others").' like%s this',@_[0..(@_>3?1:$#_)],'s'x(@_<2))}useTest::Moretests=>5;islikes(),'no one likes this';islikes('Peter'),'Peter likes this';islikes('Jacob','Alex'),'Jacob and Alex like this';islikes('Max','John','Mark'),'Max, John, and Mark like this';islikes('Alex','Jacob','Mark','Max'),'Alex, Jacob, and 2 others like this';
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);}}
deflikes(users):forfmtin['no one likes this','%s likes this','%s and %s like this','%s, %s and %s like this',]:try:returnfmt%tuple(users)exceptTypeError:passu1,u2,*rest=usersreturn'%s, %s and %s others like this'%(u1,u2,len(rest))
Python solution using a dict as switch case. Sadly I didn't had a cool idea about the "default" case wiithout using a default dict (didn't wanted to import anything)
defcreateString(persons):defFunc=lambdax:"{}, {} and {} others like this".format(x[0],x[1],len(x)-2)converter={0:lambdax:"{} likes this".format("no one"),1:lambdax:"{} likes this".format(x[0]),2:lambdax:"{} and {} like this".format(x[0],x[1]),3:lambdax:"{}, {} and {} like this".format(x[0],x[1],x[2])}returnconverter.get(len(persons),defFunc)(persons)assert(createString([])=="no one likes this")assert(createString(["Peter"])=="Peter likes this")assert(createString(["Jacob","Alex"])=="Jacob and Alex like this")assert(createString(["Max","John","Mark"])=="Max, John and Mark like this")assert(createString(["Alex","Jacob","Mark","Max"])=="Alex, Jacob and 2 others like this")
19 yo student *and* a full-time developer.
Building with Rails currently, exploring new frontiers.
I enjoy functional programming, Linux, FOSS, refactoring and mentoring :)
pubfnlikes(names:&[&str])->String{matchnames{[]=>String::from("no one likes this"),[a]=>format!("{} likes this",a),[a,b]=>format!("{} and {} like this",a,b),[a,b,c]=>format!("{}, {} and {} like this",a,b,c),[a,b,..]=>format!("{}, {} and {} others like this",a,b,names.len()-2),}}
packagelikesimport"fmt"//LikestakesasliceofpeoplewholikeapostandreturnsastringindicatingwholikesitfuncLikes(list[]string)string{likeLen:=len(list)switchlikeLen{case0:return"no one likes this"case1:returnfmt.Sprintf("%s likes this",list[0])case2:returnfmt.Sprintf("%s and %s like this",list[0],list[1])case3:returnfmt.Sprintf("%s, %s, and %s like this",list[0],list[1],list[2])default:returnfmt.Sprintf("%s, %s, and %d others like this",list[0],list[1],likeLen-2)}}
likes_test.go
packagelikesimport("testing")vartestCases=[]struct{descriptionstringinput[]stringexpectedstring}{{"no likes",[]string{},"no one likes this",},{"one like",[]string{"Mark"},"Mark likes this",},{"two likes",[]string{"Mark","Jeff"},"Mark and Jeff like this",},{"three likes",[]string{"Mark","Jeff","Bob"},"Mark, Jeff, and Bob like this",},{"many likes",[]string{"Mark","Jeff","Bob","Alice","Susan"},"Mark, Jeff, and 3 others like this",},}funcTestLikes(t*testing.T){for_,test:=rangetestCases{ifresult:=Likes(test.input);result!= test.expected {
t.Fatalf("FAIL: %s - Likes(%v): %s, expected: %s \n",test.description,test.input,result,test.expected)}t.Logf("PASS: %s \n",test.description)}}
I question the validity of this challenge. No Oxford comma??? 🧐
But on with it...
defmoduleLikeddodefby([]),do:"no one likes this"defby([friend]),do:"#{friend} likes this"defby([friend_1,friend_2]),do:"#{friend_1} and #{friend_2} like this"defby([f1,f2,f3]),do:"#{f1}, #{f2} and #{f3} like this"defby([friend_1,friend_2|friends]),do:"#{friend_1}, #{friend_2} and #{length(friends)} others like this"endLiked.by([])# "no one likes this"Liked.by(["the strippers"])# "the strippers like this"Liked.by(["the strippers","JFK"])#"the strippers and JFK like this"Liked.by(["the strippers","JFK","Stalin"])# "the strippers, JFK and Stalin like thisamerica=List.duplicate("american",300000000)# p expensive, don't actually make this large of a listLiked.by(["the strippers","JFK","Stalin"|america])# "the strippers, JFK and 300000001 others like this"
CSS
This is a "don't do this at home" type of solution. Will it work? Yes. Is is worth it? We can all agree that CSS is always worth it (:P), but in this case, it may end up with a ton of unnecessary HTML code.
The idea is to use a
ul/olto represent the list of people, and with counters keep track of the number of likes (aka people in the list). Then with pseudo-elements display the appropriate message or connector.And here is a demo on codepen:
Thanks to this challenge, I learnt that CSS counters don't increment in elements with
display: none. Which is nice.Also, I'm more of an Oxford-comma type of person, but the challenge didn't have it. (That is my excuse and I'll stick to it)
Bloody brilliant!
Some simple pattern matching with Haskell.
ruby <3
Nice!
I can't wait ruby 2.7 release!
JS, with each case defined. I went for straightforward, though there's probably room to condense this somehow given the repetition:
lol great minds think alike
Using destructuring with JS
Rust Playground
And a bit of golf with the Intl.ListFormat tool!
Here is the output:
Basically, with a bit of wibbly wobbly trickery, depending on the input length, we either call the
formatfunction with["no one"], the complete input, or the two first elements followed by the remaining quantity of items. Finally, we add (or not) ansto thelike, and return the built string!Thank god for template strings.
PHP
At first i've used a lot of
ifstatement then i got excited and tried another pointPython version (using as fewer
ifsas possible):Possible improvements: instead of
You can write:
Or - if you want to get fancy:
Or even:
But of course - all of this is redundant, since you already check for
likes_quantity > 3. So how about this:Nice, it was in fact redundant getting the message content, thanks for sharing :D
Trying with Gwion
Late to the party and I can see people have already posted a similar solution but just going to post anyway. Sometimes keeping it simple is OK :)
My simple solution in js
My code in JS
let peoples = [];
let people_likes = (p) => {
let tam = p.length;
if(tam === 0){
console.log("no one likes this");
}
else {
if(tam < 4){
console.log(
${p.join(", ")} likes this);} else {
console.log(
${p.slice(0, 2).join(", ")} and ${tam - 2} others like this);}
}
};
people_likes(peoples);
peoples.push("Peter");
people_likes(peoples);
peoples.push("Jacob");
people_likes(peoples);
peoples.push("Mark");
people_likes(peoples);
peoples.push("Alex");
people_likes(peoples);
peoples.push("Reynaldo");
people_likes(peoples);
My take at the challenge written in Elm.
Source-code
Try it online
On Ellie App.
`
Perl solution. The special array
@_contains the arguments of a subroutine, but in scalar context it returns the number of them.0xford comma included.
Here is my simple solution with PHP:
Also Python, but using a different approach:
Python solution using a dict as switch case. Sadly I didn't had a cool idea about the "default" case wiithout using a default dict (didn't wanted to import anything)
Rust:
More Go with tests:
likes.go
likes_test.go
I question the validity of this challenge. No Oxford comma??? 🧐
But on with it...
Python goes there :
A bit of functional JS
Ooh, a ternary chain. Nice 👍
[ gist.github.com/devparkk/505d7edd1... ]