Yesterday you found some shoes in your room. Each shoe is described by two values:
- type indicates if it's a left or a right shoe;
- size is the size of the shoe.
Your task is to check whether it is possible to pair the shoes you found in such a way that each pair consists of a right and a left shoe of an equal size
For:
shoes = [[0, 21],
[1, 23],
[1, 21],
[0, 23]]
the output should be true;
For:
shoes = [[0, 21],
[1, 23],
[1, 21],
[1, 23]]
the output should be false.
So I wrote the code below,added some comments
shoes = [[0, 21],
[1, 23],
[1, 21],
[0, 23]];
function pairOfShoes(shoes) {
//replace 0 with -1 so I can reduce them to 0 later if they are a pair
for (var i = 0; i < shoes.length; i++) {
if (shoes[i][0] == 0) {
shoes[i][0] = -1
}
}
//reduce the array to object with shoe size as key
function objectify(array) {
return array.reduce(function(p, c) {
p[c[1]] = (p[c[1]] != undefined ? p[c[1]] : 0) + c[0];
return p;
}, {});
}
var p = objectify(shoes);
//check for each shoe size if the value is 0
for (var x in p) {
if (p[x] != 0) {
return false;
}
}
return true;
}
console.log(pairOfShoes(shoes));
Seems convoluted to me can this code be improved?
2 Answers 2
Convert your test values where you need them
Your initial for
loop only sets each "right / left" value to -1 if it is 0. This can be done in the reduce
function itself. Also, your conditional p[c[1]] != undefined
is unnecessary, as undefined
evaluates to false, and there is no concern here about other "falsy" values such as zero.
Use Javascript's array methods
.some()
can eliminate unnecessaryfor
loops with conditionals in Javascript..values()
lets you concisely iterate through values of an object.
Combined with the arrow operator =>
, these can result in concise code that reads a little more like a natural sentence.
Applying both of the above points to your code:
shoes = [[0, 21],
[1, 23],
[1, 21],
[0, 23]];
function pairOfShoes(shoes) {
var p = shoes.reduce(function(p, c) {
p[c[1]] = (p[c[1]] || 0) + (c[0]==1 ? 1 : -1);
return p;
}, {});
if (Object.values(p).some(x => x != 0)) { return false }
else { return true };
}
console.log(pairOfShoes(shoes));
[Edit: It might also be clearer to replace your reduce
function with a `for' loop.]
-
\$\begingroup\$ I tested you answer it gives me false... \$\endgroup\$Mihai– Mihai2017年03月16日 11:32:31 +00:00Commented Mar 16, 2017 at 11:32
-
\$\begingroup\$ I'm still editing the dumb thing. \$\endgroup\$Ryan Mills– Ryan Mills2017年03月16日 11:36:59 +00:00Commented Mar 16, 2017 at 11:36
-
\$\begingroup\$ Done. And JSfiddle says it's all good. \$\endgroup\$Ryan Mills– Ryan Mills2017年03月16日 11:44:48 +00:00Commented Mar 16, 2017 at 11:44
-
\$\begingroup\$ Apparently Object.values is poorly supported on mainstream browsers, on Codewars I had to replace it with
var vals = Object.keys(p).map(function(key) { return p[key];
But it works,thanks for the effort. \$\endgroup\$Mihai– Mihai2017年03月16日 11:57:47 +00:00Commented Mar 16, 2017 at 11:57 -
\$\begingroup\$ Yeah it's probably the arrow function. That's new in ES6/ES2015. \$\endgroup\$Ryan Mills– Ryan Mills2017年03月16日 12:05:25 +00:00Commented Mar 16, 2017 at 12:05
Ryan's answer is great (and already accepted). This is just to show a few tricks:
const allPairs = (shoes) => {
const pairings = shoes.reduce((pairings, shoe) => {
const [type, size] = shoe;
pairings[size] = (pairings[size] || 0) + (type ? +1 : -1);
return pairings;
}, {});
return !Object.values(pairings).some(value => value);
};
The above uses the const
keyword, rather than var
, as it's generally better to use the stronger declaration when possible.
It also uses array destructuring to assign type
and size
, which makes the code a little clearer than using numeric indices.
Finally, rather than writing an if..else
for the return values, it just negates the result of some
and returns it directly; it's already a boolean. It also skips comparing to zero in the some
callback; zero is falsey already.
let size=c[1]
) to make it easier to understand. (2) Try and keep all your code in a function at the same level. If you are going to use a functionobjecttify
then add a function tochangeLeftFlag
and another tocheckAllEntriesAreZero
\$\endgroup\$