DEV Community

Cover image for Day 1: Who likes it? - A coding challenge with solutions
Kingsley Ubah
Kingsley Ubah

Posted on • Originally published at ubahthebuilder.tech

Day 1: Who likes it? - A coding challenge with solutions

In this weekly series, I will be taking out coding problems from CodeWars and sharing a step-by-step tutorial on how exactly I was able to solve it on my first trial. It is important to keep in mind that my solution may not be in-line with modern practices and techniques, however it is going to be correct. Which is all that really matters lol.

This is an initiative I thought up recently and I hope it helps beginners learn how to program with JavaScript.

So, let's dive in!

Who likes it?

Today's challenge is going to be quite interesting. If you use social media platforms like Facebook, you should by now know of the 'likes' feature where images and posts get liked by users and readers.

In this challenge, we are going to be creating a function which returns different customized messages depending on the number of likers a post gets.

Here are the rules:

likes[]   // "No one likes this"
likes["Jack"]     // "Jack likes this"
likes["Jack", "Jacob"]      // "Jack and Jacob likes this"
likes["Jack", "Jacob", "Jill"]      // "Jack, Jacob and Jill likes this"
likes["Jack", "Jacob", "Jill", "John"]      // "Jack, Jacob and 2 others liked this"
Enter fullscreen mode Exit fullscreen mode

As you can see, the likes() function takes in an array of users who likes a post and returns a different message depending on if one, two, three or four and more users liked the post.

I pulled this test out of a 6 kyu challenge on CodeWars.

Without further ado, let's dig in!

SOLUTION

The first step I always take when solving a coding problem is to break them down into logical steps and representing each of these steps in pseudocode.

STEP 1: CHECKING IF ANYONE LIKED IT

Define the likes function. This function will take in Array of names (strings)
First step to take inside the function is to define an if statement: Check to see if the length of the array is falsy (that is, the array is empty and no one liked the post).

If it is empty, return a string with the meaage which says "No one likes this post"

function likes ( ...names ) {
  if( !names.length) {
     return "No one likes this";
 }

// Continuation
Enter fullscreen mode Exit fullscreen mode

STEP 2: LOOPING OVER THE ARRAY AND STORING NUMBER OF LIKERS

If we got to this point, it means that there is atleast one name present in the Array. Create a count variable and set its value to zero. After you are done with that, loop through the list of name. For every iteration you make, increment the value of count by one.


let count = 0;
names.forEach(name => count++);
Enter fullscreen mode Exit fullscreen mode

STEP 3: CHECKING TO SEE HOW MANY LIKED

Step 2 was about looping through the array and increasing the count by one for every likers encountered.

Now, we are going to implement a chain of conditional statements which is geared towards returning a new message for every number of likers.

First statement checks if the count variable is one, which means that one person liked the post. If true, we will get the name of the sole liker and return the following message: insert_liker_name likes this post

Second statement checks if the count variable is two, which means that two people liked the post. If true, we will get the name of the two likers and return the following message: liker_1 and liker_2 likes this post

Third statement checks if the count variable is three, which means that three people liked the post. If true, we will get the name of the three likers and return the following message: liker_1, liker_2 and liker_3 likes this post

The fourth and final statement checks if the count variable is four or above, which means that at least four people liked the post. If true, we will first subtract two (i.e the people who will be displayed) from the number of likers, that is count. Then we will get the first two names from the list of likers and return the following message: liker_1, liker_2 and remaining_numbers likes this post

if(count == 1) {
    const firstName = names[0];
    return `${firstName} likes this post`
  } else if (count == 2) {
    const firstName = names[0]
    const secondName = names[1]
    return `${firstName} and ${secondName} likes this post`
  }
  else if (count == 3) {
    const firstName = names[0]
    const secondName = names[1]
    const thirdName = names[2]
    return `${firstName}, ${secondName} and ${thirdName} likes this post`
  } else {
    const remainder = count - 2;
    const firstName = names[0]
    const secondName = names[1]
    return `${firstName}, ${secondName} and ${remainder} others likes this post`
  }

}



Enter fullscreen mode Exit fullscreen mode

Now, lets see the full program:

function likes(...names) {
  if(!names.length) {
    return "No one likes this";
  }

  let count = 0;
  names.forEach(name => count++);

  if(count == 1) {
    const firstName = names[0];
    return `${firstName} likes this post`
  } else if (count == 2) {
    const firstName = names[0]
    const secondName = names[1]
    return `${firstName} and ${secondName} likes this post`
  }
  else if (count == 3) {
    const firstName = names[0]
    const secondName = names[1]
    const thirdName = names[2]
    return `${firstName}, ${secondName} and ${thirdName} likes this post`
  } else {
    const remainder = count - 2;
    const firstName = names[0]
    const secondName = names[1]
    return `${firstName}, ${secondName} and ${remainder} others likes this post`
  }

}

const likers = ["Jack", "Jill"]

console.log(likes(...likers));
Enter fullscreen mode Exit fullscreen mode

RESULT

JSFiddle-Code-Playground.png

JSFiddle-Code-Playground (1).png

This simple challenge was really fun for me on the first trial and I hope it was the same for you. You can copy the code and test it yourself on JS Fiddle.

If you have a better way of solving this problem, please put it down in the comments. I'd love to check it out. If you have any suggestions, I'd love to hear it!

I will be doing this every Mondays, Wednesdays and Fridays. Follow/Subscribe to this blog to be updated. I will be tackling a new challenge in public on Friday.

Until then, friends!

P/S: If you are learning JavaScript, I recently created an eBook which teaches 50 topics in hand-written notes. Check it out here

Top comments (17)

Collapse
 
jonrandy profile image
Jon Randy 🎖️ • Edited

Your function definition is wrong and doesn't match what you've stated - the function you have defined doesn't take an array at all - rather an arbitrary number of arguments that will be converted to an array. If someone were to pass an empty array to the function, rightly expecting to get the "no likes" result according to your description - it wouldn't work.

Admittedly, defining the function and calling it the way you have (using the spread operator) does make the function more flexible, but if you're going to always pass an array, or maybe extend the function to accept other parameters - then you're better off dropping the rest parameter and making the function actually accept an array rather than forming an array from its arguments

Collapse
 
ubahthebuilder profile image
Kingsley Ubah

Hi, Jon.

Thank you so much for sharing your insight.

Collapse
 
istealersn profile image
Stanley J Nadar

Thanks for sharing King.

You can concise this code a bit further and avoid repeating the same strings or values using temporals in Javascript.

Here is my version:
jsfiddle.net/iStealersn/12uetjgv/4/

Collapse
 
ubahthebuilder profile image
Kingsley Ubah

Awesome!

Thanks for sharing

Collapse
 
jamesthomson profile image
James Thomson

Some good improvements to make things more DRY, but the nested ternary's make my brain bleed. I feel like this would be much more legible using a switch or even just if/else statements.

Collapse
 
istealersn profile image
Stanley J Nadar

Yeah I agree, had the same feeling after completion. If/Else statements make it look long while switch may definitely help gotta give a shot

If you have an improved version please share, it will be helpful

Collapse
 
mattkenefick profile image
Matt Kenefick

Here's a solution that takes a few more things into account:

  • Singular vs Plural version of "like(s)"
  • How to concatenate the names "and" vs "&"
  • To use an oxford comma (always!)
  • Default name
  • Do not use conditional hell

function likes(...names) {
    const adjective = names.length > 1 ? 'like' : 'likes';
    const concatenator = 'and';

    // Empty list
    if (!names.length) names = ['No one'];

    const lastPerson = names.pop();
    const oxfordComma = names.length >= 2 ? ',' : '';
    const people = names.length 
        ? `${names.join(', ')}${oxfordComma} ${concatenator} ${lastPerson}`
        : lastPerson;
    const output = `${people} ${adjective} this`;

    console.log(output);
}


likes();
likes('Jack');
likes('Jack', 'Jill');
likes('Jack', 'Jill', 'Bill');
likes('John', 'Paul', 'George', 'Ringo');

// "No one likes this"
// "Jack likes this"
// "Jack and Jill like this"
// "Jack, Jill, and Bill like this"
// "John, Paul, George, and Ringo like this"
Enter fullscreen mode Exit fullscreen mode
Collapse
 
d3sox profile image
Nico

Nice solution. This does not say "and x others" though.

Collapse
 
mattkenefick profile image
Matt Kenefick

function likes(...names) {
    const adjective = names.length > 1 ? 'like' : 'likes';
    const concatenator = 'and';
    const maxNames = 3;
    const remainingCount = names.length - maxNames;
    const remainingCaption = remainingCount === 1 ? 'other' : 'others';

    // Empty list
    if (!names.length) {
        names = ['No one'];
    }

    const oxfordComma = names.length > 2 ? ',' : '';
    const lastPerson = remainingCount > 0 
        ? `${remainingCount} ${remainingCaption}` 
        : names.pop();
    const people = names.length === 0 
        ? lastPerson
        : `${names.slice(0, maxNames).join(', ')}${oxfordComma} ${concatenator} ${lastPerson}`;

    const output = `${people} ${adjective} this`;

    console.log(output);
}


likes();
likes('Jack');
likes('Jack', 'Jill');
likes('Jack', 'Jill', 'Bill');
likes('John', 'Paul', 'George', 'Ringo');
likes('John', 'Paul', 'George', 'Ringo', 'Archie');
likes('John', 'Paul', 'George', 'Ringo', 'Archie', 'Annie', 'Jeff', 'Abed');

// "No one likes this"
// "Jack likes this"
// "Jack and Jill like this"
// "Jack, Jill, and Bill like this"
// "John, Paul, George, and 1 other like this"
// "John, Paul, George, and 2 others like this"
// "John, Paul, George, and 5 others like this"
Enter fullscreen mode Exit fullscreen mode
Collapse
 
ubahthebuilder profile image
Kingsley Ubah

Awesome!

This is even shorter and better. Thanks for sharing.

Collapse
 
icecoffee profile image
Atulit Anand

Thanks for making this post.
It's a nice idea to share question in this forum.

Here is my version. What do you guys think

function likes(names = ["No one"]) {
  if (names.length === 0) return "No one likes this";
  let result = [];
  for (let i = 0; i < names.length; i++) {
    const name = names[i];
    if (i === 2) result.push("and", name);
    else if (i === 3) {
      result.pop();
      result.push(`${names.length - 2} others`);
      break;
    } else result.push(name);
  }
  result.push("likes this");
  return result.join(" ");
}
console.log(likes(["Jack", "Jacob", "Jill", "John", "a", "b"]));
Enter fullscreen mode Exit fullscreen mode
Collapse
 
ubahthebuilder profile image
Kingsley Ubah

It's shorter!

Collapse
 
d3sox profile image
Nico
function likes(names: string[] = []): string {
    const { length } = names;

    let who: string;
    if (length > 0) {
        const [first, second, third] = names;

        if (length > 2) {
            who = `${first}, ${second} and ${length > 3 ? `${length - 2} others` : third}`;
        } else if (length > 1) {
            who = `${first} and ${second}`;
        } else {
            who = first;
        }
    } else {
        who = 'No one';
    }

    return `${who} ${length > 1 ? 'like' : 'likes'} this`;
}

// "No one likes this"
console.log(likes([]))
// "Jack likes this"
console.log(likes(["Jack"]))
// "Jack and Jacob like this"
console.log(likes(["Jack", "Jacob"]))
// "Jack, Jacob and Jill like this"
console.log(likes(["Jack", "Jacob", "Jill"]))
// "Jack, Jacob and 2 others like this"
console.log(likes(["Jack", "Jacob", "Jill", "John"]))
Enter fullscreen mode Exit fullscreen mode

My version using destructuring. Criticism is welcome

Collapse
 
miketalbot profile image
Mike Talbot ⭐

This isn't necessary

  let count = 0;
  names.forEach(name => count++);
Enter fullscreen mode Exit fullscreen mode

No need for a loop, the number of names is always names.length

Collapse
 
ubahthebuilder profile image
Kingsley Ubah

Thank you for input.

Like I said, this is how I solved it the first time.

Collapse
 
ash_bergs profile image
Ash

I always enjoy seeing the steps each person takes to accomplishing these challenges, thanks for the write up!

Collapse
 
ubahthebuilder profile image
Kingsley Ubah

Thank you!