You probably know the "like" system from Facebook and other pages. People can "like" blog posts, pictures or other items. We want to create the text that should be displayed next to such an item.
Implement a function likes :: [String] -> String, which must take in input array, containing the names of people who like an item. It must return the display text as shown in these examples:
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"
For 4 or more names, the number in and 2 others simply increases.
Good luck!
This challenge comes from BattleRattle on CodeWars. Thank you to CodeWars, who has licensed redistribution of this challenge under the 2-Clause BSD License!
Want to propose a challenge idea for a future post? Email yo+challenge@dev.to with your suggestions!
Discussion (27)
This'd be a good use for template literals. Here's a quicky in javascript:
Sanity check:
Here is the code snippets with PHP:
For cleverness, we can solve it like this in JavaScript:
var likes = (n, l = n.length) => l == 0 ? "no one likes this" : l == 1 ? n[0] + " likes this" : l == 2 ? n[0] + " and " + n[1] + " like this" : l == 3 ? n[0] + ", " + n[1] + " and " + n[2] + " like this" : l == 4 ? n[0] + ", " + n[1] + " and " + (l - 2) + " others like this" :false console.log(likes([])) console.log(likes(["Peter"])) console.log(likes(["Jacob", "Alex"])) console.log(likes(["Max", "John", "Mark"])) console.log(likes(["Alex", "Jacob", "Mark", "Max"]))
Bonus
For best practice and cleverness, we can do this in JavaScript:
function likes (names) { var templates = [ 'no one likes this', '{name} likes this', '{name} and {name} like this', '{name}, {name} and {name} like this', '{name}, {name} and {n} others like this' ]; var idx = Math.min(names.length, 4); return templates[idx].replace(/{name}|{n}/g, function (val) { return val === '{name}' ? names.shift() : names.length; }); } console.log(likes([])) console.log(likes(["Peter"])) console.log(likes(["Jacob", "Alex"])) console.log(likes(["Max", "John", "Mark"])) console.log(likes(["Alex", "Jacob", "Mark", "Max"]))
And for the most best practice and cleverness, we can do this in JavaScript:
function likes(names) { names = 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'; } } console.log(likes([])) console.log(likes(["Peter"])) console.log(likes(["Jacob", "Alex"])) console.log(likes(["Max", "John", "Mark"])) console.log(likes(["Alex", "Jacob", "Mark", "Max"]))
I think you don't need the break after the return, it would be unreachable.
Thank you for pointing out that! 👍👍
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.
The last part is, in my opinion , the best part I've ever seen
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,
break
is not needed, as return breaks out of the switch statement.The solution in PHP
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!
This is what I got with Ruby, not a lover of it though - any Ruby devs got some alternatives?
With Rails, I'm fairly certain two of these can be solved with
to_sentence
🙌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
ref
s 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.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.
For Python
Test it:
Here's my version :)
Javascript one-liner.
The cutoff can be changed.
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...