DEV Community

dev.to staff
dev.to staff

Posted on

Daily Challenge #48 - Facebook Likes

In today's challenge, you are asked to create a like system from Facebook; a text which displays the names of people who liked an item.

For example:

likes [] must be "no one likes this"
likes ["Peter"] must be "Peter likes this"
likes ["Jacob", "Alex"] must be "Jacob and Alex like this"
likes ["Max", "John", "Mark"] must be "Max, John and Mark like this"
likes ["Alex", "Jacob", "Mark", "Max"] must be "Alex, Jacob and 2 others like this"

Note: For 4 or more names, the number in and 2 others simply increases.


Want to propose a challenge idea for a future post? Email yo+challenge@dev.to with your suggestions!

This challenge comes from BattleRattle on CodeWars. Thank you to CodeWars, who has licensed redistribution of this challenge under the 2-Clause BSD License!

Top comments (34)

Collapse
 
alvaromontoro profile image
Alvaro Montoro

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/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: "";
}

And here is a demo on codepen:

Collapse
 
alvaromontoro profile image
Alvaro Montoro

Thanks to this challenge, I learnt that CSS counters don't increment in elements with display: none. Which is nice.

Collapse
 
alvaromontoro profile image
Alvaro Montoro

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)

Collapse
 
jitheshkt profile image
Jithesh. KT

Bloody brilliant!

Collapse
 
avalander profile image
Avalander • Edited

Some simple pattern matching with Haskell.

likes :: [String] -> String
likes []        = "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 $ length xs) ++ " others like this"
Collapse
 
hanachin profile image
Seiei Miyagi • Edited

ruby <3

def likes(ls)
  case ls
  in []
    "no one likes this"
  in [a]
    format "%s likes this", a
  in [a, b]
    format "%s and %s like this", a, b
  in [a, b, c]
    format "%s, %s and %s like this", a, b, c
  in [a, b, *rest]
    format "%s, %s and %d others like this", a, b, rest.size
  end
end

p likes([]) # => "no one likes this"
p likes(["Peter"]) # => "Peter likes this"
p likes(["Jacob", "Alex"]) # => "Jacob and Alex like this"
p likes(["Max", "John", "Mark"]) # => "Max, John and Mark like this"
p likes(["Alex", "Jacob", "Mark", "Max"]) # => "Alex, Jacob and 2 others like this"
Collapse
 
ben profile image
Ben Halpern

Nice!

Collapse
 
hanachin profile image
Seiei Miyagi

I can't wait ruby 2.7 release!

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
Collapse
 
chrisachard profile image
Chris Achard

JS, with each case defined. I went for straightforward, though there's probably room to condense this somehow given the repetition:

const likes = names => {
  switch(names.length) {
    case 0:
      return "no one likes this"
    case 1:
      return `${names[0]} likes this`
    case 2:
      return `${names[0]} and ${names[1]} like this`
    case 3:
      return `${names[0]}, ${names[1]} and ${names[2]} like this`
    default:
      return `${names[0]}, ${names[1]} and ${names.length - 2} others like this`
  }
}
Collapse
 
jasman7799 profile image
Jarod Smith

lol great minds think alike

Collapse
 
andre000 profile image
André Adriano • Edited

Using destructuring with JS

const likeText = (likes = []) => {
    if(!likes.length) return 'no one likes this';

    const [first, second, third, ...rest] = likes
    if(!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`;
}
Collapse
 
jay profile image
Jay

Rust Playground

fn fb_likes(names: &[&str]) -> String {
    match names.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
        ),
    }
}
Collapse
 
ynndvn profile image
La blatte

And a bit of golf with the Intl.ListFormat tool!

f=(n)=>(b=n.length<2,a=new Intl.ListFormat`en-GB`,(n.length>3?a.format([n[0],n[1],n.length-2+' others']):a.format(n.length?n:['no one']))+` like${b?'s':''} this`)

Here is the output:

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!

Collapse
 
fennecdjay profile image
Jérémie Astor

Trying with Gwion

fun void likes(string array[]) {
  array.size() => const int sz;
  switch(sz) {
    case 0:
      <<< "no one", " likes this" >>>;
      break;
    case 1:
      <<< array[0], " likes this" >>>;
      break;
    case 2:
      <<< array[0], " and ", array[1], " like this" >>>;
      break;
    case 3:
      <<< 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;
Collapse
 
jasman7799 profile image
Jarod Smith
function likes(people) {
  switch (people.length) {
    case 0:
      return 'no one likes this';
    case 1:
      return `${people[0]} likes this`;
    case 2:
      return `${people[0]} and ${people[1]} like this`;
    case 3:
      return `${people[0]}, ${people[1]} and ${people[2]} like this`;
    default:
      return `${people[0]}, ${people[1]} and ${people.length - 2} others like this`;
  }
}

Thank god for template strings.

Collapse
 
celyes profile image
Ilyes Chouia • Edited

PHP

$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;