PHP | Array - gibt es soetwas wie GROUP BY ?
Mein Name ist Nobody
- php
Hi,
ich habe ein PHP Array gefüllt mit Zahlenwerten: $array = array("1", "6", "1", "8");
Ich suche eine PHP Funktion, die mir die häufigkeit der Werte zählen kann. Also Wert 1 ist 2 mal, 6 =1 usw. Ähnlich der MYSQL Funktion Group by Count.
Meine erste Idee wäre ein foreach, und ein weiteres Array bauen dann mit gegenchecks und zählern, falls vorhanden +1 ...
Das muss doch aber auch einfacher gehen oder?
Danke Nobody
Moin,
Ich suche eine PHP Funktion, die mir die häufigkeit der Werte zählen kann. Also Wert 1 ist 2 mal, 6 =1 usw. Ähnlich der MYSQL Funktion Group by Count.
Die Funktion array_count_values() klingt doch da ganz vielversprechend …
Gruß
Tobias
Hallo Tobias,
vielen Dank für deine Nachricht. Du hast den Nagel auf den Kopf getroffen, genau so eine Funktion habe ich gesucht.
Daumen hoch.
@@Mein Name ist Nobody
Ich suche eine PHP Funktion, die mir die häufigkeit der Werte zählen kann.
Wo genau suchst du?
Ich hab einfach auf php.net nach „Array“ gesucht, lande auf Arrays und finde auf Anhieb in der Liste die Methode „Zählt die Werte eines Arrays“.
🖖 Живіть довго і процвітайте
Danke für den Hinweis. Ich hatte es wohl übersehen.
Нехай сила буде з тобою
Hallo,
ich habe ein PHP Array gefüllt mit Zahlenwerten:
$array = array("1", "6", "1", "8");
ergänzend zu den Lösungshinweisen, die du schon bekommen hast:
Das sind keine Zahlenwerte, sondern Strings.
Einen schönen Tag noch
Martin
ergänzend zu den Lösungshinweisen, die du schon bekommen hast: Das sind keine Zahlenwerte, sondern Strings.
Und schon haben wir ein typisches PHP-Problem.
Ich habe mal das Beispiel aus der Doc probiert.
<?php
$array = array(1, "hello", 1, "world", "hello");
print_r(array_count_values($array));
Ausgabe:
Array
(
[1] => 2
[hello] => 2
[world] => 1
)
Man könnte jetzt etwas wie „toll“ denken. Aber:
<?php
$array = array(1, "hello", "1", "world", "hello", 1.9);
print_r(array_count_values($array));
Warning: array_count_values(): Can only count string and
integer values, entry skipped in /home/fastix/tmp/2.php on line 3
Array
(
[1] => 2
[hello] => 2
[world] => 1
)
was auch so NICHT stimmt, denn var_dump($array)
sagt:
array(6) {
[0]=>
int(1)
[1]=>
string(5) "hello"
[2]=>
string(1) "1" ### INT 1 != STRING 1: falsch gezählt!
[3]=>
string(5) "world"
[4]=>
string(5) "hello"
[5]=>
float(1.9) ### Nicht gezählt!
}
Die Doc erklärt auch, wie diverse Werte in Keys umgewandelt werden - und zeigt die Hölle
Hallo,
Und schon haben wir ein typisches PHP-Problem.
… Die Doc erklärt auch, wie diverse Werte in Keys umgewandelt werden - und zeigt die Hölle
Aber das halte ich für nicht relevant. Man hat entweder ein Array mit gleichartigen Daten, dann hat man das Typumwandlungsproblem nicht, oder das Array ist ein Datenwust aus unterschiedlichsten Typen. Dann ist dessen Zählung aber auch irrelevant, oder?
Das Konzept, bei dem man in dein konstruiertes Problem läuft, möchte ich nicht wirklich sehen…
Gruß
Kalk
Hallo,
Und schon haben wir ein typisches PHP-Problem.
… Die Doc erklärt auch, wie diverse Werte in Keys umgewandelt werden - und zeigt die Hölle
Aber das halte ich für nicht relevant.
Hehe!
Bei einem Array mit den Werten [ 0.4, 1.2, 0.4, 0.8]
funktioniert array_count_values()
auch nicht.
Du meinst ernsthaft, DAS sei „nicht relevant“?
Hallo,
Bei einem Array mit den Werten
[ 0.4, 1.2, 0.4, 0.8]
funktioniertarray_count_values()
auch nicht.Du meinst ernsthaft, DAS sei „nicht relevant“?
Im Prinzip ja. Für welche(n) Analyse, Anwendung oder usecase braucht man die jeweilige Anzahl der floatwerte?
Gruß
Kalk
Hallo,
Bei einem Array mit den Werten
[ 0.4, 1.2, 0.4, 0.8]
funktioniertarray_count_values()
auch nicht.Du meinst ernsthaft, DAS sei „nicht relevant“?
Im Prinzip ja. Für welche(n) Analyse, Anwendung oder usecase braucht man die jeweilige Anzahl der floatwerte?
usecase: Kindergeburtstag beim Raketenwilli:
Es stehen 4 Teller mit je 1/8, 1/8, 1/4, 1/2-Stücken von ganzen Torten auf dem Tisch.
Klein Raketenwilli wird gerade 9, ist verfressen wie ein Regiment Russen, darf die 1/4-Torten-Stücke und die 1/2-Torten-Stücke sofort futtern, wenn er ohne selbst zu zählen herausbekommt, wie viele Stücke dieser Größen auf den Tellern liegen. Mutti hat es schwierig gemacht und die Stücke jeweils verwürfelt. Klein Raketenwilli ist außerdem faul und will gar nicht selbst zählen!
Mit meiner (inzwischen erweiterten) Klasse klappt das:
<?php
class strong_array_values_counter {
protected $keys=[];
protected $counts=[];
function __construct( $arr ) {
foreach ( $arr as $v ) {
if ( ! in_array( $v, $this->keys, true ) ) {
$pos = count( $this->keys ) ;
$this->keys[$pos] = $v;
$this->counts[$pos] = 1;
} else {
$pos = $this->findPos( $v );
$this->counts[$pos]++;
}
}
}
private function findPos( $v ) {
for ( $i=0; $i < count( $this->keys ); $i++ ) {
if ( $this->keys[$i] === $v ) {
return $i;
}
}
return false;
}
public function get_Keys_Values() {
$ret=[];
for ( $i=0; $i < count( $this->keys); $i++ ) {
$ret[] = [ $this->keys[ $i ], $this->counts[ $i ] ];
}
return $ret;
}
public function get_Counts_By_Value( $v ) {
$pos = $this->findPos( $v );
return $this->counts[ $pos ];
}
public function get_Counts_BetWeen( $v1, $v2, $includet=true, $intToFloat=false ) {
if ( $intToFloat and gettype( $v1 ) == 'integer') settype($v1, 'double' );
if ( $intToFloat and gettype( $v2 ) == 'integer') settype($v2, 'double' );
$typeOfV1 = gettype( $v1 );
$typeOfV2 = gettype( $v2 );
if ( $typeOfV1 != $typeOfV2 ) {
trigger_error('Die übergebenen Werte sind nicht typgleich. Es findet kein Vergleich statt.', E_USER_WARNING );
return false;
}
if ( $v1 > $v2 ) {
$t = $v1; $v1 = $v2; $v2 = $t;
}
$founds = 0;
for ( $i=0; $i < count( $this->keys ); $i++ ) {
$t = $this->keys[ $i ];
if ( $intToFloat and gettype( $t ) == 'integer') settype( $t, 'double' );
if ( $includet ) {
if (
gettype( $t ) == $typeOfV1
and $t >= $v1
and $t <= $v2
) {
$founds += $this->counts[ $i ];
}
} else {
if (
gettype( $t ) == $typeOfV1
and $t > $v1
and $t < $v2
) {
$founds += $this->counts[ $i ];
}
}
}
return $founds;
}
}
<?php
### Herstellen
$ar = [];
$teller = [ (1/8), (1/8), (1/4), (1/2) ];
### Servieren
for ( $i = 0; $i < 4; $i++ ) {
shuffle( $teller );
foreach ( $teller as $stück ) {
array_push( $ar, $stück ) ;
}
}
### Muttis Kontrolle:
print_r( $ar );
### Nicht SELBST zählen:
require_once 'strong_array_values_counter.php';
$o = new strong_array_values_counter( $ar );
echo $o->get_Counts_BetWeen( (1/4), (1/2), true, true ) . PHP_EOL;
Anmerkung: Für den Raketenwilli und seine Cousine wurden einst tatsächlich je 2 Torten gemacht. Vergebliche Mühsal diese zu schneiden ...
Anmerkung: Das ist natürlich nicht der einzige usecase. Nimm Messreihen, Ausschussquoten, ...
Anmerkung: Meine Klasse kann neben Strings, Floats und Integers sogar Objekte, Arrays und anderes Zeug gruppiert zählen, welches sich als Elemente eines Arrays im Speicher tummeln.
Hallo,
Ok, bei Torten (und Weckern) muss ich mich geschlagen geben…
Gruß
Kalk
@@Tabellenkalk
Ok, bei Torten (und Weckern) muss ich mich geschlagen geben…
WAS? DU KRIEGST 28 DURCH 7 NICHT RAUS?
🖖 Живіть довго і процвітайте
Hallo,
WAS? DU KRIEGST 28 DURCH 7 NICHT RAUS?
Kurzfassung: stell dir vor du hast 28 Torten und musst um 7 Uhr raus…
Gruß
Kalk
@@Raketenwilli
Das ist natürlich nicht der einzige usecase. Nimm Messreihen
Halte ich für keinen Usecase. Wenn da zwei Messwerte „gleich“ sind, sind sie das im Rahmen der Messgenauigkeit. Aber sie sind nicht wirklich gleich.
Heißt, ich sehe den Usecase nicht, array_count_values()
auf ein Array von Floats anwenden zu wollen.
🖖 Живіть довго і процвітайте
Hallo,
Das ist natürlich nicht der einzige usecase. Nimm Messreihen
Halte ich für keinen Usecase. Wenn da zwei Messwerte „gleich“ sind, sind sie das im Rahmen der Messgenauigkeit. Aber sie sind nicht wirklich gleich.
sp isses, und selbst wenn sie im Rahmen der Darstellungsgenauigkeit, z.B. der Darstellung im IEEE-Fließkommaformat, gleich sind (was theoretisch möglich wäre), ist das in der Regel irrelevant.
Bei Messwerten ist normalerweise nur relevant, dass sie innerhalb einer vorgegebenen Spanne oder diesseits/jenseits einer bestimmten Schwelle liegen.
Heißt, ich sehe den Usecase nicht,
array_count_values()
auf ein Array von Floats anwenden zu wollen.
+1
Einen schönen Tag noch
Martin
Hi,
Halte ich für keinen Usecase. Wenn da zwei Messwerte „gleich“ sind, sind sie das im Rahmen der Messgenauigkeit. Aber sie sind nicht wirklich gleich.
Eben. Floats/Doubles niemals auf Gleichheit prüfen, immer nur auf eine Differenz kleiner Epsilon (wobei Epsilon größer sein muß als die kleinste darstellbare Differenz)
cu,
Andreas a/k/a MudGuard
Wie, wann und warum array_count_values()
untauglich ist und sogar falsche Ergebnisse liefert habe ich gezeigt.
Als „Raketenwilli“ will ich natürlich so ein Problem gelöst sehen… Hier mein erster Ansatz:
<?php
$array = array("1", "hello", 1, "world", "hello");
echo "Das Array:\n";
var_dump( $array );
$strong_counter = New strong_array_values_counter( $array );
echo "\nDas Objekt:\n";
var_dump( $strong_counter);
echo "Werte und Vorkommen in zwei Arrays:\n";
var_dump( $strong_counter->get_Keys_Values() );
echo "\nVorkommen von 1 und \"1\":\n";
echo 'STR "1":' . $strong_counter->get_Counts_By_Value( "1" ) . PHP_EOL;
echo 'INT 1 :' . $strong_counter->get_Counts_By_Value( 1 ) . PHP_EOL;
class strong_array_values_counter {
protected $keys=[];
protected $counts=[];
function __construct( $arr ) {
foreach ( $arr as $v ) {
if ( ! in_array( $v, $this->keys, true ) ) {
$pos = count( $this->keys ) ;
$this->keys[$pos] = $v;
$this->counts[$pos] = 1;
} else {
$pos = $this->findPos( $v );
$this->counts[$pos]++;
}
}
}
private function findPos( $v ) {
for ( $i=0; $i < count( $this->keys ); $i++ ) {
if ( $this->keys[$i] === $v ) {
return $i;
}
}
return false;
}
public function get_Keys_Values() {
$ret=[];
for ( $i=0; $i < count( $this->keys); $i++ ) {
$ret[] = [ $this->keys[ $i ], $this->counts[ $i ] ];
}
return $ret;
}
public function get_Counts_By_Value( $v ) {
$pos = $this->findPos( $v );
return $this->counts[ $pos ];
}
}
Putput:
Das Array:
array(5) {
[0]=>
string(1) "1"
[1]=>
string(5) "hello"
[2]=>
int(1)
[3]=>
string(5) "world"
[4]=>
string(5) "hello"
}
Das Objekt:
object(strong_array_values_counter)#1 (3) {
["keys":protected]=>
array(4) {
[0]=>
string(1) "1"
[1]=>
string(5) "hello"
[2]=>
int(1)
[3]=>
string(5) "world"
}
["types":protected]=>
array(0) {
}
["counts":protected]=>
array(4) {
[0]=>
int(1)
[1]=>
int(2)
[2]=>
int(1)
[3]=>
int(1)
}
}
Werte und Vorkommen in zwei Arrays:
array(4) {
[0]=>
array(2) {
[0]=>
string(1) "1"
[1]=>
int(1)
}
[1]=>
array(2) {
[0]=>
string(5) "hello"
[1]=>
int(2)
}
[2]=>
array(2) {
[0]=>
int(1)
[1]=>
int(1)
}
[3]=>
array(2) {
[0]=>
string(5) "world"
[1]=>
int(1)
}
}
Vorkommen von 1 und "1":
STR "1":1
INT 1 :1