0

Possible Duplicate:
Implode array with “, ” and add “and ” before last item

I'm customising a WordPress theme and I have created some checkboxes in the user profile page in the admin, 3 to be exact. When a user checks each box the value of that box is saved in an array calle $goals when they save their profile. This all works great.

On a template page I'm doing some tests on how to display certain content based on what goals the user has selected so I have created the following code which checks whether the array contains each value on it's own and then combinations of goals together and then echos specific content based on those selections. It works just fine but I feel the code is bloated and could be streamlined. This is something I'm always looking to do with my code. I would really appreciate your thoughts on how I can achieve the same results with less code. Thanks.

$goals = get_user_meta( $userID, 'goals', $single );

if (in_array('Weight Loss', $goals, true) && !in_array('Improve Fitness', $goals, true) && !in_array('Improve Health', $goals, true)) {
    echo 'Weight Loss';
} elseif (in_array('Improve Fitness', $goals, true) && !in_array('Weight Loss', $goals, true) && !in_array('Improve Health', $goals, true)) {
    echo 'Improve Fitness';
} elseif (in_array('Improve Health', $goals, true) && !in_array('Improve Fitness', $goals, true) && !in_array('Weight Loss', $goals, true)) {
    echo 'Improve Health';
} elseif (in_array('Weight Loss', $goals, true) && in_array('Improve Fitness', $goals, true) && !in_array('Improve Health', $goals, true)) {
    echo 'Weight Loss and Improve Fitness';
} elseif (in_array('Weight Loss', $goals, true) && !in_array('Improve Fitness', $goals, true) && in_array('Improve Health', $goals, true)) {
    echo 'Weight Loss and Improve Health';
} elseif (!in_array('Weight Loss', $goals, true) && in_array('Improve Fitness', $goals, true) && in_array('Improve Health', $goals, true)) {
    echo 'Improve Fitness and Improve Health';
} elseif (in_array('Weight Loss', $goals, true) && in_array('Improve Fitness', $goals, true) && in_array('Improve Health', $goals, true)) {
    echo 'Weight Loss, Improve Fitness and Improve Health';
} else {
    echo 'Nothing set';
}
Community
  • 1
  • 1
Gareth Daine
  • 4,016
  • 5
  • 40
  • 67
  • 1
    Uhm... [Implode array with “, ” and add “and ” before last item](http://stackoverflow.com/questions/8586141/implode-array-with-and-add-and-before-last-item)? – deceze Oct 03 '12 at 08:38
  • @deceze but that doesn't directly deal with an empty array; i.e. it doesn't disambiguate between an array with empty strings and an empty array. – Ja͢ck Oct 03 '12 at 09:05
  • Then `array_filter` your array before or otherwise make sure there are no empty strings in there, then make one special case for an empty array. – deceze Oct 03 '12 at 09:06

2 Answers2

2

To represent the list of goals in a human readable form:

if (count($goals) > 1) {
    echo join(', ', array_slice($goals, 0, -1)) . ' and ' . end($goals);
} elseif ($goals) {
    echo $goals[0];
} else {
    echo "Nothing set";
}

Depending on how many items you have, the code will return either "X" / "X and Y" / "X, Y and Z".

In the case of more than one item, it does the following:

  1. Take the items up to but not including the last item - using array_slice() and put a comma in between them - using join().
  2. Add the word " and " and the value of the last item.

To narrow down the $goals array to just those items you mentioned:

$goals = array_intersect(array('Weight Loss', 'Improve Fitness', 'Improve Health'), $goals);

It strips out all values except the ones you're interested in, in your case just three of them. Depending on your situation, you may not need this code though.

Ja͢ck
  • 170,779
  • 38
  • 263
  • 309
  • Thanks for the reply. I don't really understand what's going on here as I'm not an expert at PHP but I will give it a try and see what happens, I would like to understand your answer in more detail though. Gives me some food for thought and a research starting point. Thanks. – Gareth Daine Oct 03 '12 at 09:35
  • @GarethDaine updated the answer, hope it makes more sense now. – Ja͢ck Oct 03 '12 at 09:45
  • Just thinking. The echo statements in my code are simply placeholders to show that my if statements are working the code that goes there will be WordPress custom post type content based on the selection. That said, how does the 'array_slice' function factor in? Also, what if I need to know if the code returns Y and Z or X and Z? – Gareth Daine Oct 03 '12 at 10:13
  • @GarethDaine well, it's not very clear from the question, I assumed your original code was already working, so I wrote an equivalent. – Ja͢ck Oct 03 '12 at 10:14
  • That code does work, sorry. It does exactly what I want. But looking through your explanation it looks as though your code only returns "X" / "X and Y" / "X, Y and Z" as you mentioned, which is not what my code does. Also, I'm not trying to echo out what has been selected, I'm simply trying to find out what has been selected and then display content based on that. Thanks. – Gareth Daine Oct 03 '12 at 11:17
  • The echo statements are merely placeholders. – Gareth Daine Oct 03 '12 at 11:18
  • @GarethDaine So, it's solved then? :) – Ja͢ck Oct 03 '12 at 12:07
  • Yes, my code works I'm simply looking to streamline it and was after advice. – Gareth Daine Oct 03 '12 at 15:14
0

If you do not want to simply concatenate the strings as your example suggests, the more streamlined version of that code would be something like this:

sort($goals);

switch ($goals) {
    case array('Weight Loss') :
        ...
        break;

    case array('Improve Fitness', 'Weight Loss') :
        ...
        break;

    ...
}

The important thing here being that the elements in both arrays are in the same order, therefore the initial sort and the comparison elements being ordered alphabetically.

Having said that, there's got to be a better way of handling this than handling all possible permutations, since that goes up exponentially as you add more options. You should usually loop over the collection of goals, for each goal do something, then output some aggregate value:

$output = array();

foreach ($goals as $goal) {
    switch ($goal) {
        case 'Weight Loss' :
            $output[] = 'I want to lose weight.';
            break;

        case 'Improve Fitness' :
            $output[] = ...
            break;

        ...
    }
}

echo join("\n", $output);

With a really sensible OOP based structure, where each goal is defined as an individual object, this could look even more like:

$output = array();

foreach ($goals as $goal) {
    $output[] = $goal->objectiveDescription();
}

echo join("\n", $output);

In other words, the way you're approaching the problem is insufficient. It's hard to suggest something without knowing what you're actually trying to do though.

deceze
  • 510,633
  • 85
  • 743
  • 889