3

I want to separate an array with comma and word.

This is the code that i make:

$array = array( 'user1', 'user2', 'user3', 'user4', 'user5' );
$last = array_pop( $array );
$string = count( $array ) ? implode( ", ", $array ) . " and " . $last : $last;

printf( 'Authors: %s', $string );

My code print this:

Authors: user1, user2, user3, user4 and user5

I successfully made a code to implode the array with a comma and search for the last key and separate it with a word 'and'.

But that's what I want but I failed after more than 2 days of work on this:

Authors: user1, user2, and user3 and 2 others.

6
  • Is your goal only printing it ? or you want to make new array ? Commented Sep 5, 2018 at 22:07
  • @M4HdYaR First thank you very much for trying to help me. Second with the same array that i used in my code. I want to print the first and second users and then add word 'and' before the third user and if more in the array add x others. Commented Sep 5, 2018 at 22:09
  • Related: stackoverflow.com/q/18476587/2943403 Commented Sep 5, 2018 at 22:20
  • @mickmackusa Here's the array $array = array( 'user1', 'user2', 'user3', 'user4', 'user5' ); I want from this array print this: Authors: user1, user2, and user3 and 2 others. ( I want to print the first and second users and separate them with a comma and then add the word 'and' before the third user and if more in the array add x others. ). Are you understand now? Commented Sep 5, 2018 at 22:27
  • Will you always have at least 3 elements? Do we need to accommodate the possibility of 0 elements, 1 element, 2 elements as well? Commented Sep 5, 2018 at 22:30

4 Answers 4

3

While I always look for the clever calculated process for handling a task like this, I'll offer a much more pedestrian alternative. (For the record, I hate writing a battery of if-elseif-else conditions almost as much as I hate the verbosity of a switch-case block.) For this narrow task, I am electing to abandon my favored array functions and conditionally print the values with their customized delimiters.

While this solution is probably least scalable on the page, it is likely to be the easiest to comprehend (relate the code to its generated output). If this is about "likes" or something, I don't really see a large demand for scalability -- but I could be wrong.

Pay close attention to the 2-count case. My solution delimits the elements with and instead of , which seems more English/human appropriate.

Code: (Demo)

$arrays[] = array();
$arrays[] = array('user1');
$arrays[] = array('user1', 'user2');
$arrays[] = array('user1', 'user2', 'user3');
$arrays[] = array('user1', 'user2', 'user3', 'user4');
$arrays[] = array('user1', 'user2', 'user3', 'user4', 'user5');

foreach ($arrays as $i => $array) {
    echo "TEST $i: ";
    if (!$count = sizeof($array)) {
        echo "nobody";
    } elseif ($count == 1) {
        echo $array[0];
    } elseif ($count == 2) {
        echo "{$array[0]} and {$array[1]}";
    } elseif ($count == 3) {
        echo "{$array[0]}, {$array[1]}, and {$array[2]}";
    } else {
        echo "{$array[0]}, {$array[1]}, {$array[2]}, and " , $count - 3, " other" , ($count != 4 ? 's' : '');
    }
    echo "\n---\n";
}

Output:

TEST 0: nobody
---
TEST 1: user1
---
TEST 2: user1 and user2
---
TEST 3: user1, user2, and user3
---
TEST 4: user1, user2, user3, and 1 other
---
TEST 5: user1, user2, user3, and 2 others
---

p.s. A more compact version of the same handling:

Code: (Demo)

if (!$count = sizeof($array)) {
    echo "nobody";
} elseif ($count < 3) {
    echo implode(' and ', $array);
} else{
    echo "{$array[0]}, {$array[1]}";
    if ($count == 3) {
        echo ", and {$array[2]}";
    } else {
        echo ", {$array[2]}, and " , $count - 3, " other" , ($count != 4 ? 's' : '');
    }
}

And finally, here's an approach that "doctors up" the array and prepends and to the final element. I think anyway you spin this task, there's going to be a degree of convolution.

Code: (Demo)

$count = sizeof($array);
if ($count < 3) {
    echo implode(' and ', $array);
} else {
    if ($count == 3) {
        $array[2] = "and {$array[2]}";
    } else {
        $more = $count - 3;
        array_splice($array, 3, $more, ["and $more other" . ($more > 1 ? 's' : '')]);
    }
    echo implode(', ', $array);
}

During a CodeReview, I realized a "pop-prepend-push" technique: https://codereview.stackexchange.com/a/255554/141885


From PHP8, match() is also available. An implementation might look like this: (Demo)

$count = count($array);
echo match ($count) {
         0 => 'nobody',
         1 => $array[0],
         2 => implode(' and ', $array),
         3 => "{$array[0]}, {$array[1]}, and {$array[2]}",
         default => "{$array[0]}, {$array[1]}, {$array[2]}, and " . $count - 3 . " other" . ($count != 4 ? 's' : '')
     };
Sign up to request clarification or add additional context in comments.

2 Comments

Great answer mick :)
I keep thinking of different ways to do it. ...I should stop doing this and start my actual work. (damn StackOverflow addiction)
2

Here's one way to do it:

Start by imploding the first two array elements. (array_splice will remove them from $array.)

$string = implode(', ', array_splice($array, 0, 2));

Add the third one if it's there. (array_shift will remove it from $array too.)

if ($array) {
    $string .= ', and ' . array_shift($array);
}

Count the rest and add them, if any are left.

if ($n = count($array)) {
    $string .= " and $n other". ($n > 1 ? 's' : '');
    //                           conditional pluralization
}

3 Comments

I pulled a comma out, but this looks good. plus 1 3v4l.org/0IXgU
...I may still post an alternative solution if I can forge a valuable one.
@Don't I made an unmentioned accommodation for 2-element cases. Have a look at my new post.
1

There are several ways to do it, one simple way :

First you should get the numbers of elements in your array to see if it's more than 3 or not.

$count = count( $array) ;

Then if it's more than 3 , you can make your string:

if($count>3){
    $string= $array[0] . 'and' . $array[1] . 'and' . $array[2] . 'and' . ($count - 3) . "others";
}else{
    $last = array_pop( $array );
    $string = count( $array ) ? implode( ", ", $array ) . " and " . $last : $last;
    //I used exactly your code , you have several ways to do it
    //Attention ... This code may not work when your array has only one element
}
printf( 'Authors: %s', $string );

If you want to know more about PHP arrays you can use this link , a quick tutorial

Or the documentation

4 Comments

I think there's something wrong with your code it's print to me: Authors: -3others. Can you add your full code?
Could used in the first response: $string= $array[0] . ' and ' . $array[1] . ' and ' . $array[2] . ' and ' . ($count - 3) . ' others ' variable $othersnot needed. Just ()missing arround to $count - 3
M4HdYaR Thank you I got to know what you are trying to do in your answer and this helps me to improve your answer more. @JérômeTeisseire thank you i have done this before your comment :).
This answer does not produce the desired output.
1

I suggest you to think your problem as a function that you can Unit-Test so it becomes easier to build and you can flexibilize your solution.

  • Use counters to track your array: total, first chunk, tail
  • Consider any special cases like 2 elements, 3 elements, etc.
  • Get the last item with array_pop
  • Use array_slice to get the first chunk from the "take N" argument.
  • Implode and concat as required to get the desired result

Here an example of how it could be.

<?php

function niceAuthorsPrint(array $authors, $takeCount){

  $totalAuthors = count( $authors );
  $tailCount = $totalAuthors - $takeCount;

  $first = array_slice($authors, 0, $takeCount);

  $othersLabel = $tailCount == 1 ? 'other' : 'others';

  $string = implode( ", ", $first );

  if($tailCount > 0){
     $string .= " and " . $tailCount . ' ' . $othersLabel;      
  }

  return $string;
}

// take 3
echo niceAuthorsPrint(array( 'user1', 'user2', 'user3', 'user4', 'user5' ), 3) ."\n";

// take 4
echo niceAuthorsPrint(array( 'user1', 'user2', 'user3', 'user4', 'user5' ), 4) ."\n";

// take 5
echo niceAuthorsPrint(array( 'user1', 'user2', 'user3', 'user4', 'user5' ), 5) ."\n";

?>

Will output:

user1, user2, user3 and 2 others
user1, user2, user3, user4 and 1 other
user1, user2, user3, user4, user5

Working example here


Alternative

An alternative for handling special cases and printing the last item value.

<?php

// array of authors, number of authors to take first
function niceAuthorsPrint(array $authors, $takeCount){

  $totalAuthors = count( $authors );

  if($totalAuthors >= 3 && $takeCount >= $totalAuthors)
  {
      $takeCount = 2;
  }

  if($totalAuthors == 2 && $takeCount >= $totalAuthors)
  {
      $takeCount = 1;
  }

  $last = array_pop($authors);

  $tailCount = $totalAuthors - $takeCount;

  $first = array_slice($authors, 0, $takeCount);

  $othersLabel = $tailCount == 1 ? $last : $tailCount . ' others';

  $string = implode( ", ", $first );

  if($tailCount > 0){
     $string .= " and " . $othersLabel;      
  }

  return $string;
}

// take 3
echo niceAuthorsPrint(array( 'user1', 'user2', 'user3', 'user4', 'user5' ), 3) ."\n";

// take 4
echo niceAuthorsPrint(array( 'user1', 'user2', 'user3', 'user4', 'user5' ), 4) ."\n";

// take 5
echo niceAuthorsPrint(array( 'user1', 'user2', 'user3', 'user4', 'user5' ), 5) ."\n";

// take original count, take first three as default
echo niceAuthorsPrint(array( 'user1', 'user2', 'user3', 'user4', 'user5' ), 5) ."\n";

// take original count, take first three as default
echo niceAuthorsPrint(array( 'user1', 'user2', 'user3'), 3) ."\n";

// take original count, take first three as default
echo niceAuthorsPrint(array( 'user1', 'user2'), 2) ."\n";

Will print:

user1, user2, user3 and 2 others
user1, user2, user3, user4 and user5
user1, user2 and 3 others
user1, user2 and 3 others
user1, user2 and user3
user1 and user2

Feel free to adjust to your needs.

Working code example

3 Comments

Why you edit your answer? With your answer before any edits, you made absolutely what I want. Just one something you forgot only that for the third user separates it with a word 'and' not a comma like this: user1, user2, and user3 and 2 others. and this case happens only if the count of the array greater than 3 and if equal 3 then the results will be: user1, user2, and user3.
You can see the edits history of the answer. Here the link to the previous code: 3v4l.org/e76Id
I already make the code that I want for my project, I just tell you how to make your answer complete to mark it as the best answer. Your old code working without any issues just complete it if you need as I told you in my comment. Anyway thank you very much for your efforts :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.