DEV Community

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

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

Kingsley Ubah on August 04, 2021

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...
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!