Implodieren Sie ein Array mit "," und fügen Sie "und" vor dem letzten Element hinzu

74

Dieses Array enthält eine Liste von Elementen, und ich möchte daraus eine Zeichenfolge machen, aber ich weiß nicht, wie das letzte Element ein & / und davor anstelle eines Kommas haben soll.

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

soll werden

coke, sprite and fanta

Dies ist die reguläre implodierende Funktion:

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

Was ist ein einfacher Weg, um es zu tun?

lisovaccaro
quelle
4
Warum nicht das letzte Element des Arrays abschneiden, bevor der Rest implodiert? Und dann einfach. = Konzentriere dich auf deine Saite.
Djot

Antworten:

115

Ein Longliner, der mit einer beliebigen Anzahl von Artikeln funktioniert:

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

Oder wenn Sie die Ausführlichkeit wirklich bevorzugen:

$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);

Der Punkt ist, dass dieses Schneiden, Zusammenführen, Filtern und Verbinden alle Fälle, einschließlich 0, 1 und 2 Elemente, ohne zusätzliche if..elseAnweisungen korrekt behandelt . Und es ist zufällig zu einem Einzeiler zusammenklappbar.

täuschen
quelle
17
+1 für alles in einer Zeile, -1 für die Rückkehr in 5 Monaten, um herauszufinden, was es zu tun versucht.
Mike Purcell
3
+1 für Klugheit, aber nicht die am besten lesbare Lösung der Welt: P
Interrobang
4
Oh, zögern Sie nicht, dies in einzelne Schritte aufzuteilen, wenn Sie möchten. Es ist nur so, dass für diese Vorgehensweise keine ifsoder Schleifen erforderlich sind und alle in einem Ausdruck ausgeführt werden können. Genau deshalb nenne ich das einen Long-Liner . Und natürlich würden Sie dies in eine Funktion namens setzen joinWithLastSeparator(array $array, $separator = ' and '), damit Sie wissen, was es 5 Monate später tut. : o)
täuschen
2
Ich habe diesen Beitrag gerade wegen eines Duplikats gesehen und eine etwas schmutzigere, aber auch etwas kürzere Linie bekommen. dachte, ich werfe das einfach hier echo implode(" and ", array_filter(array_reverse([array_pop($array), implode(", ", $array)])));
rein
3
Fünf Jahre später, und ich muss zugeben, dass ich wahrscheinlich meine eigene Antwort ablehnen würde ... Ich bin immer noch stolz auf die Tatsache, dass es ein einziger Ausdruck ist, aber ... hum, yeah ...; o)
täuschen
92

Ich bin mir nicht sicher, ob ein Einzeiler die eleganteste Lösung für dieses Problem ist.

Ich habe das vor einiger Zeit geschrieben und es nach Bedarf abgelegt:

/**
 * 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;
}

Sie müssen "und" nicht als Join-Zeichenfolge verwenden, es ist effizient und funktioniert mit 0 bis zu einer unbegrenzten Anzahl von Elementen:

// 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'));
Wütender Dan
quelle
6
+1 Sauberste, logischste und am einfachsten zu verfolgende und unterstützt eine unbekannte Anzahl von Elementen. Wunderschönen!
random_user_name
2
Viel einfacher zu verstehen als die akzeptierte Antwort.
Will
+1 für diese Lösung. Lesbar und gut. Die Rückgabe von null ist für mich jedoch etwas seltsam. Ich ziehe es vor, eine leere Zeichenfolge zurückzugeben, wenn das Array keine Elemente enthält.
Mitko Delibaltov
26

Sie können das letzte Element einfügen und es dann mit dem Text verbinden:

$yourArray = ('a', 'b', 'c');
$lastItem = array_pop($yourArray); // c
$text = implode(', ', $yourArray); // a, b
$text .= ' and '.$lastItem; // a, b and c
JercSi
quelle
1
Es funktioniert auch nicht mit sizeof ($ yourArray) == 0. Dann ist die richtige Lösung, zuerst die Länge des Arrays zu überprüfen und dann den obigen Code auszuführen. wenn size == 0, dann nichts tun; Wenn Größe == 1, wird das erste Element zurückgegeben. Andernfalls führen Sie den obigen Code aus.
JercSi
7
Es funktioniert wie ein Zauber, wenn eine Bedingung hinzugefügt wird if (count($yourArray) > 1)... Danke :)
Enissay
Die Lösung von Enrique funktioniert für 1 Element (und 0 Elemente) ohne zusätzliche Wenns.
ChrisV
15

Versuche dies:

$str = array_pop($array);
if ($array)
    $str = implode(', ', $array)." and ".$str;
Enrique
quelle
Gute einfache Lösung - funktioniert für 0, 1, 2 und 3+ Elemente und kann bei Bedarf so angepasst werden, dass vor dem letzten Element ein Komma steht
ChrisV
1
Das einzige Problem bei diesem ist, wenn ich ein Komma vor dem letzten Element haben möchte, wenn drei oder mehr Elemente vorhanden sind, aber in einigen Fällen möglicherweise nur zwei Elemente vorhanden sind, die bei Verwendung des gleichen Codes ein fehlerhaftes Komma hinzufügen würden. Dies wird in 99% der Situationen funktionieren, obwohl ich denke, also +1.
Eckstein
4

Eine weitere mögliche kurze Lösung:

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

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

Es funktioniert gut mit einer beliebigen Anzahl von Werten.

Vision
quelle
2

Ich weiß, ich bin viel zu spät für die Antwort, aber das ist sicherlich ein besserer Weg, es zu tun?

$list = array('breakfast', 'lunch', 'dinner');
$list[count($list)-1] = "and " . $list[count($list)-1];
echo implode(', ', $list);
Jack B.
quelle
1
Hat den Nachteil, immer ein Komma vor dem letzten Element (vor dem 'und') zu haben
ChrisV
Es ist immer noch die richtige Grammatik. Ich stimme jedoch Ihrem Punkt zu. Enriques Antworten scheinen meinen ähnlich zu sein, lösen aber dieses Problem :)
Jack B
Funktioniert, wenn die Liste mehr als ein Element enthält, jedoch nicht, wenn die Liste dynamisch ist. (Leicht mit einem ifWrapper zu lösen )
random_user_name
1

Mein Ansprechpartner, ähnlich wie Enriques Antwort, behandelt aber optional das Oxford-Komma.

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;
}
JJ Wright
quelle
1

Dies kann mit array_fillund erfolgen array_map. Es ist auch ein Einzeiler (scheint, dass viele sie genießen), aber für die Lesbarkeit formatiert:

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

Nicht die optimalste Lösung, aber dennoch.

Hier ist die Demo .

sevavietl
quelle
0

Versuche dies

$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);
Astha
quelle
0

Versuche dies,

<?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 . ", ";
}
?>
Planet x
quelle
0

Ich habe dies nur anhand der Vorschläge auf dieser Seite codiert. Ich habe meinen Pseudocode in den Kommentaren hinterlassen, falls jemand ihn brauchte. Mein Code unterscheidet sich von anderen hier, da er Arrays unterschiedlicher Größe unterschiedlich behandelt und die Oxford-Komma-Notation für Listen mit drei oder mehr verwendet.

    /**
     * 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;
        }
    }
zkent
quelle
0

Das ist zu diesem Zeitpunkt ziemlich alt, aber ich dachte, es kann nicht schaden, meine Lösung dem Stapel hinzuzufügen. Es ist ein bisschen mehr Code als andere Lösungen, aber damit bin ich einverstanden.

Ich wollte etwas mit ein wenig Flexibilität, deshalb habe ich eine Dienstprogrammmethode erstellt, mit der Sie festlegen können, wie das endgültige Trennzeichen aussehen soll (damit Sie beispielsweise ein kaufmännisches Und verwenden können) und ob ein Oxford-Komma verwendet werden soll oder nicht. Es behandelt auch Listen mit 0, 1 und 2 Elementen ordnungsgemäß (etwas, was einige der Antworten hier nicht tun)

$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);
}
Josh Janusch
quelle
0

OK, das wird also ziemlich alt, aber ich muss sagen, ich denke, die meisten Antworten sind sehr ineffizient mit mehreren Imploden oder Array-Zusammenführungen und ähnlichen Dingen, die alle weitaus komplexer sind als nötig, IMO.

Warum nicht einfach:

implode(',', array_slice($array, 0, -1)) . ' and ' . array_slice($array, -1)[0]
greenbutterfly
quelle
Dies führt zu einem Hinweis, da Sie eine Konvertierung von Array in Zeichenfolge durchführen.
CupOfTea696
1
Ja, ich habe das gestern selbst bemerkt, als ich meine eigene Lösung vergessen habe, also habe ich sie gegoogelt! Im letzten Teil fehlt ein Array-Index. Ich werde ihn jetzt bearbeiten und hinzufügen.
Greenbutterfly
0

Einfacher human_implode mit Regex.

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
uruapanmexicansong
quelle
0

Eine andere, wenn auch etwas ausführlichere Lösung, die ich mir ausgedacht habe. In meiner Situation wollte ich die Wörter im Array Plural machen, daher wird am Ende jedes Elements ein "s" hinzugefügt (es sei denn, das Wort endet bereits mit "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" 
        }
    }
}

Ausgänge:

F150s, Express, CR-Vs, Rav4s, and Silverados
Alex Russell
quelle
-1

Es ist schneller als die Lösung von deceze und funktioniert mit riesigen Arrays (1M + Elemente). Der einzige Fehler beider Lösungen ist eine schlechte Interaktion mit einer Zahl 0 in Arrays mit weniger als drei Elementen, da array_filter verwendet wird.

echo implode(' and ', array_filter(array_reverse(array_merge(array(array_pop($array)), array(implode(', ',$array))))));
Błażej Klisz
quelle