用“,”放大数组,并在最后一项之前添加“ and”


76

这个数组包含一个项目列表,我想将其转换为字符串,但是我不知道如何使最后一个项目前带有&/和而不是逗号。

1 => coke 2=> sprite 3=> fanta

应该成为

coke, sprite and fanta

这是常规的爆破功能:

$listString = implode(', ', $listArrau);

有什么简单的方法吗?


4
为什么不在内插其余元素之前先切掉数组的最后一个元素?然后只将。=简化为您的字符串。
djot 2011年

Answers:


117

可处理任何数量项目的长衬板:

echo join(' and ', array_filter(array_merge(array(join(', ', array_slice($array, 0, -1))), array_slice($array, -1)), 'strlen'));

或者,如果您真的更喜欢冗长:

$last  = array_slice($array, -1);
$first = join(', ', array_slice($array, 0, -1));
$both  = array_filter(array_merge(array($first), $last), 'strlen');
echo join(' and ', $both);

关键是,这种切片,合并,过滤和联接可以正确处理所有情况,包括0、1和2项目,而无需额外的if..else语句。而且它恰好可以折叠成单线。


17
+1表示全部获得一条线,-1表示必须从现在起5个月后再去弄清楚它要做什么。
Mike Purcell

3
+1代表聪明,但不是世界上最易读的解决方案:P
Interrobang

4
哦,如果愿意,可以将其分解为单个步骤,只是这种方式不需要任何ifs或循环,并且可以在一个表达式中完成。这就是为什么我称其为长话。当然,您可以将其放在一个名为中的函数中joinWithLastSeparator(array $array, $separator = ' and '),以便在接下来的5个月内知道它的作用。:o)
deceze

2
刚刚因为重复而看到了此帖子,但脏了一点,但线条短了很多。以为我只是把它丢在这里echo implode(" and ", array_filter(array_reverse([array_pop($array), implode(", ", $array)])));
Franz Gleichmann '16

3
五年后,我不得不承认我可能会拒绝我自己的答案……我仍然为它只是一个表达而感到自豪,但是……哼,是的;; o)
deceze

95

我不确定单一衬板是否是解决此问题的最佳方法。

我前一阵子写了这个,然后按要求放入:

/**
 * Join a string with a natural language conjunction at the end. 
 * https://gist.github.com/angry-dan/e01b8712d6538510dd9c
 */
function natural_language_join(array $list, $conjunction = 'and') {
  $last = array_pop($list);
  if ($list) {
    return implode(', ', $list) . ' ' . $conjunction . ' ' . $last;
  }
  return $last;
}

您不必使用“ and”作为连接字符串,它非常有效,并且可以处理从0到不限数量的项目:

// null
var_dump(natural_language_join(array()));
// string 'one'
var_dump(natural_language_join(array('one')));
// string 'one and two'
var_dump(natural_language_join(array('one', 'two')));
// string 'one, two and three'
var_dump(natural_language_join(array('one', 'two', 'three')));
// string 'one, two, three or four'
var_dump(natural_language_join(array('one', 'two', 'three', 'four'), 'or'));

6
+1最干净,最合逻辑且易于遵循的方法,并且支持未知数量的项目。美丽!
random_user_name 2014年

2
比接受的答案更容易理解。
2016年

该解决方案+1。可读且良好。但是返回null对我来说有点奇怪。如果数组没有元素,我更喜欢返回空字符串。
Mitko Delibaltov

27

您可以弹出最后一个项目,然后将其与文本合并:

$yourArray = ('a', 'b', 'c');
$lastItem = array_pop($yourArray); // c
$text = implode(', ', $yourArray); // a, b
$text .= ' and '.$lastItem; // a, b and c

1
同样,它不适用于sizeof($ yourArray)==0。然后正确的解决方案将是,首先检查数组的长度,然后执行上面的代码。如果size == 0,则什么也不做;如果size == 1,则返回第一项;否则执行上面的代码。
JercSi 2011年

7
添加条件时,它就像一种魅力if (count($yourArray) > 1)...谢谢:)
Enissay 2013年

Enrique的解决方案适用于1个元素(和0个元素),而没有多余的“ if”。
ChrisV 2014年

15

尝试这个:

$str = array_pop($array);
if ($array)
    $str = implode(', ', $array)." and ".$str;

好简单的解决方案-适用于0,1,2,和3+的元件,并且可适于具有最终元件之前一个逗号如果需要的话
ChrisV

1
唯一的问题是,如果有三个或更多元素,我是否要在最后一个元素前加逗号,但是在某些情况下我可能只有两个元素,如果使用相同的代码,则会添加一个错误的逗号。尽管我认为这可以在99%的情况下使用,所以+1。
Eckstein 2014年

4

另一个可能的简短解决方案:

$values = array('coke', 'sprite', 'fanta');

$values[] = implode(' and ', array_splice($values, -2));
print implode(', ', $values);  // "coke, sprite and fanta"

它适用于任意数量的值。


2

我知道即时答案的方法,但是可以肯定,这是一种更好的方法?

$list = array('breakfast', 'lunch', 'dinner');
$list[count($list)-1] = "and " . $list[count($list)-1];
echo implode(', ', $list);

1
缺点是总是在最后一个元素之前(“和”之前)使用逗号
ChrisV 2014年

它仍然是正确的语法。但是,我同意你的观点。恩里克(Enrique)的答案似乎与我的相似,但解决了这个问题:)
杰克B

当列表具有多个项目时有效,但当列表为动态时则无效。(使用if包装器即可轻松解决)
random_user_name 2014年

1

我的研究与Enrique的答案类似,但是可以选择处理牛津逗号。

public static function listifyArray($array,$conjunction='and',$oxford=true) {
    $last = array_pop($array);
    $remaining = count($array);
    return ($remaining ?
        implode(', ',$array) . (($oxford && $remaining > 1) ? ',' : '') . " $conjunction "
        : '') . $last;
}

1

这可以通过array_fill和来完成array_map。它也是单行代码(似乎很多人喜欢它们),但为便于阅读而设置格式:

$string = implode(array_map(
    function ($item, $glue) { return $item . $glue; }, 
    $array,
    array_slice(array_fill(0, count($array), ', ') + ['last' => ' and '], 2)
));

虽然不是最佳解决方案,但仍然如此。

这是演示


0

尝试这个

$arr = Array("coke","sprite","fanta");
$str = "";
$lenArr = sizeof($arr);
for($i=0; $i<$lenArr; $i++)
{
    if($i==0)
        $str .= $arr[$i];
    else if($i==($lenArr-1))
        $str .= " and ".$arr[$i];
    else
        $str .= " , ".$arr[$i];
}
print_r($str);

0

尝试这个,

<?php
$listArray = array("coke","sprite","fanta");

foreach($listArray as $key => $value)
{
 if(count($listArray)-1 == $key)
  echo "and " . $value;
 else if(count($listArray)-2 == $key)
  echo $value . " ";
 else
  echo $value . ", ";
}
?>

0

我只是根据本页上的建议对此进行了编码。我在注释中留下了伪代码,以防有人需要。我的代码与这里的其他代码不同,因为它对不同大小的数组的处理方式不同,并且对三个或三个以上的列表使用牛津逗号表示法。

    /**
     * Create a comma separated list of items using the Oxford comma notation.  A
     * single item returns just that item.  2 array elements returns the items
     * separated by "and".  3 or more items return the comma separated list.
     *
     * @param array $items Array of strings to list
     * @return string List of items joined by comma using Oxford comma notation
     */
    function _createOxfordCommaList($items) {
        if (count($items) == 1) {
            // return the single name
            return array_pop($items);
        }
        elseif (count($items) == 2) {
            // return array joined with "and"
            return implode(" and ", $items);
        }
        else {
            // pull of the last item
            $last = array_pop($items);

            // join remaining list with commas
            $list = implode(", ", $items);

            // add the last item back using ", and"
            $list .= ", and " . $last;

            return $list;
        }
    }

0

在这一点上,这已经很老了,但是我认为将我的解决方案添加到堆栈中不会有什么坏处。它比其他解决方案多了一些代码,但是我可以接受。

我想要一些具有灵活性的东西,所以我创建了一个实用程序方法,该方法可以设置最终的分隔符应该是什么(例如,您可以使用&符)以及是否使用牛津逗号。它还可以正确处理包含0、1和2项的列表(这里有很多答案是不正确的)

$androidVersions = ['Donut', 'Eclair', 'Froyo', 'Gingerbread', 'Honeycomb', 'Ice Cream Sandwich', 'Jellybean', 'Kit Kat', 'Lollipop', 'Marshmallow'];

echo joinListWithFinalSeparator(array_slice($androidVersions, 0, 1)); // Donut
echo joinListWithFinalSeparator(array_slice($androidVersions, 0, 2)); // Donut and Eclair
echo joinListWithFinalSeparator($androidVersions); // Donut, Eclair, Froyo, Gingerbread, Honeycomb, Ice Cream Sandwich, Jellybean, Kit Kat, Lollipop, and Marshmallow
echo joinListWithFinalSeparator($androidVersions, '&', false); // Donut, Eclair, Froyo, Gingerbread, Honeycomb, Ice Cream Sandwich, Jellybean, Kit Kat, Lollipop & Marshmallow

function joinListWithFinalSeparator(array $arr, $lastSeparator = 'and', $oxfordComma = true) {
    if (count($arr) > 1) {
        return sprintf(
            '%s%s %s %s', 
            implode(', ', array_slice($arr, 0, -1)),
            $oxfordComma && count($arr) > 2 ? ',':'',
            $lastSeparator ?: '', 
            array_pop($arr)
        );
    }

    // not a fan of this, but it's the simplest way to return a string from an array of 0-1 items without warnings
    return implode('', $arr);
}

0

好的,这已经很老了,但是我不得不说,我认为大多数答案在多次内爆或数组合并以及诸如此类的事情下效率都非常低下,远比必要的IMO复杂得多。

为什么不只是:

implode(',', array_slice($array, 0, -1)) . ' and ' . array_slice($array, -1)[0]

这引起了通知,因为您正在执行数组到字符串的转换。
CupOfTea696 '17

1
是的,昨天我忘记了自己的解决方案时,发现自己如此用Google搜索!最后一部分缺少数组下标,现在我将对其进行编辑和添加。
greenbutterfly

0

使用正则表达式进行简单的human_implode

function human_implode($glue = ",", $last = "y", $elements = array(), $filter = null){
    if ($filter) {
        $elements = array_map($filter, $elements);
    }

    $str = implode("{$glue} ", $elements);

    if (count($elements) == 2) {
        return str_replace("{$glue} ", " {$last} ", $str);
    }

   return preg_replace("/[{$glue}](?!.*[{$glue}])/", " {$last}", $str);
}

print_r(human_implode(",", "and", ["Joe","Hugh", "Jack"])); // => Joe, Hugh and Jack

0

我想出了另一个解决方案,尽管稍微有些冗长。在我的情况下,我想使数组中的单词复数,因此这将在每个项目的末尾添加一个“ s”(除非单词已经以“ s”结尾):

$models = array("F150","Express","CR-V","Rav4","Silverado");
foreach($models as $k=>$model){ 
    echo $model;
    if(!preg_match("/s|S$/",$model)) 
        echo 's'; // add S to end (if it doesn't already end in S)
    if(isset($models[$k+1])) { // if there is another after this one.
        echo ", "; 
        if(!isset($models[$k+2])) 
            echo "and "; // If this is next-to-last, add  ", and" 
        }
    }
}

输出:

F150s, Express, CR-Vs, Rav4s, and Silverados

-1

它比deceze的解决方案更快,并且可以处理大型数组(超过1M个元素)。两种解决方案的唯一缺点是,由于使用了array_filter,在少于三个元素的数组中与数字0的交互性较差。

echo implode(' and ', array_filter(array_reverse(array_merge(array(array_pop($array)), array(implode(', ',$array))))));
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.