Reputation: 945
Here's the challenge: Write a function that takes in a fruit array and return an array of colors that can be found in this array. Fruits of the same color will return the same value but not repeat itself.
For example:
whatFruitColors(['apple', 'orange', 'mango']);
// returns ['red', 'orange']
I am trying to solve this with a switch statement because I would like to use "fall-through" to process all the statements. Can someone please tell me what I am doing wrong?
var whatFruitColors = function(fruitArray){
var fruitColors = [];
switch(fruitArray){
case fruitArray.indexOf('pineapple' || 'banana') > -1):
fruitColors.push('yellow');
case fruitArray.indexOf('mango' || 'orange') > -1):
fruitColors.push('orange');
case fruitArray.indexOf('apple') > -1):
fruitColors.push('red');
break;
}
console.log(fruitColors);
return fruitColors;
}
whatFruitColors(['pineapple','banana','apple','mango','orange']);
Upvotes: 3
Views: 5108
Reputation: 150080
Others have explained where you went wrong, but I thought I'd add an answer to show that sometimes when you are trying to create an array without duplicates it can be simpler to use a plain object as a working variable and then just take the keys from that object at the end - saves having to do any testing of whether a particular item already exists.
If you have:
var fruits = {};
...then you can say:
fruits['yellow'] = true;
...as many times as you like and the fruits
object will still have only one property named yellow
. (The value you assign to the property can be anything, because the point is just to create the property, but I suggest true
because it seems more logical than other possible values.)
In context (still using a switch
statement, though you could do this with .reduce()
or a series of if
statements or whatever the other answer did):
var whatFruitColors = function(fruitArray){
var fruitColors = {};
fruitArray.forEach(function(fruit) {
switch(fruit){
case 'pineapple':
case 'banana':
fruitColors['yellow'] = true;
break;
case 'mango':
case 'orange':
fruitColors['orange'] = true;
break;
case 'apple':
fruitColors['red'] = true;
break;
}
});
console.log(fruitColors);
return Object.keys(fruitColors);
}
console.log(whatFruitColors(['pineapple','banana','apple','mango','orange']));
Upvotes: 2
Reputation: 101730
Seems like you're trying to use a switch
statement for no real reason, when simple if
statements would suffice. This will give you the "fall-through" flow that you want, because it's just a series of statements.
Also, using 'oneValue' || 'anotherValue'
inside .indexOf
won't do what you're trying to do. fruitArray.indexOf('pineapple' || 'banana')
is functionally identical to fruitArray.indexOf('pineapple')
. The 'banana'
part will be ignored.
var whatFruitColors = function(fruitArray) {
var fruitColors = [];
if (fruitArray.indexOf('pineapple') > -1 ||
fruitArray.indexOf('banana') > -1) {
fruitColors.push('yellow');
}
if (fruitArray.indexOf('mango') > -1 ||
fruitArray.indexOf('orange') > -1) {
fruitColors.push('orange');
}
if (fruitArray.indexOf('apple') > -1) {
fruitColors.push('red');
}
console.log(fruitColors);
return fruitColors;
}
whatFruitColors(['pineapple', 'banana', 'apple', 'mango', 'orange']);
You could also use a cleaner and more extensible implementation that uses .filter
, .some
, and .map
:
function whatFruitColors(fruits) {
var fruitColors = [{
color: 'red',
fruits: ['apple']
},
{
color: 'yellow',
fruits: ['banana', 'pineapple']
},
{
color: 'orange',
fruits: ['mango', 'orange']
}
];
return fruitColors.filter(function(item) {
return item.fruits.some(function(fruit) {
return fruits.indexOf(fruit) > -1;
});
})
.map(function(item) {
return item.color;
});
}
console.log(whatFruitColors(['banana', 'mango', 'orange']));
Upvotes: 1
Reputation: 5281
If you need a much less elegant solution than Array.reduce, then:
var whatFruitColors = function (fruitArray) {
var fruitColors = [];
for (var i = 0; i < fruitArray.length; i++) {
var item = fruitArray[i];
switch (item) {
case 'pineapple':
case 'banana':
if (fruitColors.indexOf('yellow') === -1) {
fruitColors.push('yellow');
}
break;
case 'mango':
case 'orange':
if (fruitColors.indexOf('orange') === -1) {
fruitColors.push('orange');
}
break;
case 'apple':
if (fruitColors.indexOf('red') === -1) {
fruitColors.push('red');
}
break;
}
}
console.log(fruitColors);
return fruitColors;
};
whatFruitColors(['pineapple', 'banana', 'apple', 'mango', 'orange']);
Upvotes: 3
Reputation: 1055
Not quite what you were looking for -- and not as elegant as Tom's solution, wow -- but it does use a switch
statement. (I thought about putting the conditionals in the switch cases, but it seemed neater to just filter the result at the end.)
var whatFruitColors = function(fruitArray){
var fruitColors = [];
for (let fruit of fruitArray) {
switch(fruit){
case 'pineapple':
case 'banana':
fruitColors.push('yellow');
break;
case 'mango':
case 'orange':
fruitColors.push('orange');
break;
case 'apple':
fruitColors.push('red');
break;
}
}
let reducedFruits = fruitColors.filter((elem, index, self) => {
return index === self.indexOf(elem);
});
console.log(reducedFruits);
return reducedFruits;
}
whatFruitColors(['pineapple','banana','apple','mango','orange']);
Upvotes: 1
Reputation: 9137
I don't think switch
is a good fit for this. And I think your "fall-through" pattern is guaranteed to fail: every case
statement after the first that is triggered will also execute.
You can make this work with a switch
, but you'd have to abandon your "fall-through," and you'll need to iterate through the individual fruits.
Alternatively, if you just want to avoid any looping, the most straightforward solution is to use a series of non-exclusive if
statements, like so:
function whatFruitColors(fruitList) {
var results = [];
if(fruitList.indexOf('apple' ) >= 0 && results.indexOf('red' ) === -1) fruitList.push('red' );
if(fruitList.indexOf('banana' ) >= 0 && results.indexOf('yellow') === -1) fruitList.push('yellow');
if(fruitList.indexOf('kiwi' ) >= 0 && results.indexOf('green' ) === -1) fruitList.push('green' );
if(fruitList.indexOf('mango' ) >= 0 && results.indexOf('orange') === -1) fruitList.push('orange');
if(fruitList.indexOf('orange' ) >= 0 && results.indexOf('orange') === -1) fruitList.push('orange');
if(fruitList.indexOf('pineapple') >= 0 && results.indexOf('yellow') === -1) fruitList.push('yellow');
return results;
}
whatFruitColors(['pineapple','banana','apple','mango','orange']);
This will work, but it's frankly crude, and there's a lot of redudant code. Also, maintaining this -- i.e. adding new fruits, maintaining the list of fruit+color associations -- will be a pain in the ass.
This is a perfect use-case for Array.reduce
. Here is a better solution:
function whatFruitColors(fruitList) {
// a static lookup "table" that declares the color of every fruit
var FRUIT_COLORS = {
'apple': 'red',
'banana': 'yellow',
'kiwi': 'green',
'mango': 'orange',
'orange': 'orange',
'pineapple': 'yellow'
};
return fruitList.reduce(function(foundColors, thisFruit) {
var thisFruitColor = FRUIT_COLORS[thisFruit];
if(foundColors.indexOf(thisFruitColor) === -1) {
foundColors.push(thisFruitColor);
}
return foundColors;
}, []);
}
whatFruitColors(['pineapple','banana','apple','mango','orange']);
Upvotes: 1