Ein Array in Gruppen mit Vielfachen/Potenzen von 10/N unterteilen (Thema: PHP Beispiele)

Wie ein Array in Gruppen von Elementen mit Vielfachen/Potenzen eines bestimmten Wertes eingeteilt werden kann

URL: http://www.rither.de/a/informatik/php-beispiele/arrays/ein-array-in-gruppen-mit-vielfachen-potenzen-von-10-n-unterteilen/

1. Werte in Blöcke mit Vielfachen von 10 einteilen

In diesem Beispiel ist es das Ziel, eine Menge von Werten in Blöcke mit Vielfachen von 10 zu unterteilen. So soll aus array(5, 7, 11, 32) etwa array(0=>array(5, 7), 1=>array(11), 3=>array(32)) werden. Dementsprechend muss ein mehrdimensionales Array generiert werden, welches als Schlüssel die Nummer des Vielfachen enthält (0 für 0 bis 9, 1 für 10 bis 19 usw.) und als Wert ein Array mit allen gefundenen Vielfachen aus dem zum Schlüssel gehörenden Bereich.

Die Implementierung erfolgt über eine foreach-Schleife. Diese iteriert über ein Beispielarray $arr mit mehreren Werten und erzeugt ein Rückgabearry $out mit dem oben beschriebenen Aufbau. Dementsprechend muss während jeder Iteration zunächst bestimmt werden, zu welchem Vielfachen von 10 der Wert gehört. Das ist nicht schwer und kann für einen Wert $val mit (int)($val / 10) erledigt werden — es wird also durch 10 geteilt und der Nachkommabereich abgeschnitten. Ist bekannt, zu welchen Vielfachen der Wert gehört, muss er nur noch zu demjenigen Array hinzugefügt werden, das dieses Vielfache repräsentiert. Vorher sollte man noch prüfen, ob bereits irgendein Wert zu diesem Array hinzugefügt wurde, sonst kann es zu Fehlermeldungen kommen, wenn das Array noch nicht definiert ist, man aber trotzdem versucht, das Element anzuhängen.

PHP-Code: Anwendung einer foreach-Schleife zum Einteilen der Werte eines Arrays in Gruppen mit Vielfachen von 10
<?php
	$arr = array(3, 5, 13, 31, 39, 44, 45, 46, 97);
	$out = array();
	foreach ($arr as $key=>$val) {
		// Zum wievielten Vielfachen von 10 gehört $val?
		$c = (int)($val / 10);
		// Gibt es zu diesem Vielfachen schon mindestens einen Wert?
		if (isset($out[$c])) {
			// ... ja, einfach zum Array hinzufügen
			$out[$c][] = $val;
		} else {
			// ... nein, neues Array mit diesem Wert erzeugen
			$out[$c] = array($val);
		}
	}
	
	// Ausgabe nach Muster
	//   Block (von bis): Werte (als kommagetrennte Auflistung)
	foreach ($out as $key=>$values) {
		echo($key*10 . "-" . (($key+1)*10 - 1) . ": " . implode(', ', $values) . "\n");
	}
?>

HTML-Code: Ausgabe
0-9: 3, 5
10-19: 13
30-39: 31, 39
40-49: 44, 45, 46
90-99: 97


2. Werte in Blöcke mit Vielfachen von N einteilen

Die Verallgemeinerung des vorherigen Beispiels von 10 auf N Elemente pro Block ist sehr einfach: Es wird schlicht 10 durch N (hier $of) ausgetauscht. Im nachfolgenden Beispiel wird dies gezeigt. In diesem wurde der Code zusätzlich in eine eigene Funktion chunkByMultiplesOf($arr, $of) verschoben, welche das Array $arr in Blöcke von $of Elemente einteilt.

PHP-Code: Verallgemeinerung der Einteilung in Gruppen von Werten
<?php
	function chunkByMultiplesOf($arr, $of) {
		// Prüfen, ob $of überhaupt ein Integer und ungleich 0 ist
		if (!is_int($of) || $of===0) {
			throw new Exception("Bilden von Gruppen/Chunks nicht möglich, da der übergebene Wert für \$of entweder kein Integer oder Null ist.");
		}
		
		$out = array();
		foreach ($arr as $key=>$val) {
			// Statt 10 wird hier einfach $of verwendet
			$c = (int)($val / $of);
			if (isset($out[$c])) {
				$out[$c][] = $val;
			} else {
				$out[$c] = array($val);
			}
		}
		
		return $out;
	}
	
	$arr = array(3, 5, 13, 31, 39, 44, 45, 46, 97);
	$multiplesOf = 7; // hier beispielhaft einteilen in Vielfache von 7 statt 10
	$chunks = chunkByMultiplesOf($arr, $multiplesOf);
	
	// Ausgabe
	foreach ($chunks as $key=>$values) {
		echo($key*$multiplesOf . "-" . (($key+1)*$multiplesOf - 1) . ": " . implode(', ', $values) . "\n");
	}
?>

HTML-Code: Ausgabe
0-6: 3, 5
7-13: 13
28-34: 31
35-41: 39
42-48: 44, 45, 46
91-97: 97


3. Werte in Blöcke mit Potenzen von 10 einteilen

Ein ähnliches Problem wie in den vorherigen Beispielen ist die Einteilung der Werte eines Arrays in Potenzen von 10. Die Bereiche sollen diesmal also nicht 0-9, 10-19, 20-29 usw. lauten, sondern stattdessen 0-9, 10-99, 100-999 usw. (bzw. 100 bis (101-1), 101 bis (102-1), 102 bis (103-1), ...). Die Funktion, die dies erreicht, ist nahezu identisch zur der in den vorherigen Beispielen. Einzig die Berechnung des Schlüssels für den Block des Rückgabearrays ist diesmal anders. Diese ändert sich von (int)($val / 10) zu (int)(log10($val)), da der Exponent x aus 10x = $val bestimmt werden muss. (log10() ist der natürliche Logarithmus. log10($val) gibt also zurück, wie oft 10 mit sich selbst multipliziert werden muss, um auf $val zu kommen.)

Das einzige Problem, das sich bei diesem Verfahren ergibt, ist der genaue Umgang mit Werten kleiner als 1. Negative Werte können nicht abgebildet werden, bei der 0 wiederum ist nur eine Annäherung möglich. Ein Erfassen der Werte von 0 bis 1 wäre zwar möglich (Exponent läge dann zwischen 0 und 1), diese passen aber nicht wirklich ins Rückgabearray. Bisher ist dessen Aufbau so, dass der Schlüssel 0 für den Bereich 100 bis 101-1, der Schlüssel 1 für 101 bis 102-1 usw. gilt, also 1 bis 9, 10 bis 19 usw. In dieses Muster passt der Block von 0 bis 1 nicht rein. Spätestens bei der Ausgabe müsste man zwangsweise ein if-else-Statement verwenden, um ihn zu erfassen und von den anderen Blöcken ≥1 zu trennen. Das würde die Handhabung der Rückgabe erschweren und zwangsweise früher oder später zu Missverständnnissen führen. Daher wird hier vereinfachend die Regel aufgestellt, dass nur Integer größer oder gleich 1 erfasst werden sollen (nur die Floats aus dem Bereich 0 bis 1 nicht zuzulassen wäre auch nicht sonderlich konsequent).

PHP-Code: Alle Potenzen von zehn in einem Array in Gruppen einteilen
<?php
	$arr = array(3, 5, 13, 31, 39, 44, 45, 117, 118, 417, 1111, 8535);
	$out = array();
	foreach ($arr as $key=>$val) {
		// Nur Integer größer oder gleich 1
		if (is_int($val) && $val>=1) {
			// Zum wievielten Exponenten gehört der Wert?
			$c = (int)(log10($val));
			if (isset($out[$c])) {
				$out[$c][] = $val;
			} else {
				$out[$c] = array($val);
			}
		}
	}
	
	// Ausgabe
	foreach ($out as $key=>$values) {
		// pow(10, $x) ergibt 10 hoch $x
		// Würde man Werte von 0 bis 1 zulassen, dann müsste hier zwangsweise eine if-else-Bedingung stehen
		echo(pow(10, $key) . "-" . (pow(10, $key+1) - 1) . ": " . implode(', ', $values) . "\n");
	}
?>

HTML-Code: Ausgabe
1-9: 3, 5
10-99: 13, 31, 39, 44, 45
100-999: 117, 118, 417
1000-9999: 1111, 8535


4. Werte in Blöcke mit Potenzen von N einteilen

Die Verallgemeinerung der vorherigen Funktion von Zehnerpotenzen auf Potenzen von N ist auch hier sehr einfach. Wieder muss schlicht die 10 durch N (hier $of) ausgetauscht werden. Wie im zweiten Beispiel wird wieder eine eigene Funktion erstellt, die Blöcke mit Zehnerpotenzen erstellt. Der Parameter N (bzw. $of) wird am Anfang der Funktion geprüft und muss mindestens zwei, sowie ein Integer sein (Potenzen von 1 zu suchen wäre wohl wenig erfolgversprechend).

PHP-Code: Werte eines Arrays in Gruppen mit Potenzen von N einteilen
<?php
	function chunkByPowersOf($arr, $of) {
		// Es sind nur Integer als N erlaubt und N muss mindestens 2 sein
		if (!is_int($of) || $of<=1) {
			throw new Exception("Bilden von Gruppen/Chunks nicht möglich, da der übergebene Wert für \$of entweder kein Integer oder kleiner/gleich 1 ist.");
		}
		
		$out = array();
		foreach ($arr as $key=>$val) {
			if (is_int($val) && $val>=1) {
				// hier 10 durch $of austauschen
				$c = (int)(log($val, $of));
				if (isset($out[$c])) {
					$out[$c][] = $val;
				} else {
					$out[$c] = array($val);
				}
			}
		}
		
		return $out;
	}
	
	$arr = array(3, 5, 13, 31, 39, 44, 45, 117, 118, 417, 1111, 8535);
	$powersOf = 7; // Diesmal Potenzen von 7 statt 10 suchen
	$chunks = chunkByPowersOf($arr, $powersOf);
	
	// Ausgabe
	foreach ($chunks as $key=>$values) {
		echo(pow($powersOf, $key) . "-" . (pow($powersOf, $key+1) - 1) . ": " . implode(', ', $values) . "\n");
	}
?>

HTML-Code: Ausgabe
1-6: 3, 5
7-48: 13, 31, 39, 44, 45
49-342: 117, 118
343-2400: 417, 1111
2401-16806: 8535


Um unsere Webseite für Sie optimal zu gestalten und fortlaufend verbessern zu können, verwenden wir Cookies. Durch die weitere Nutzung der Webseite stimmen Sie der Verwendung von Cookies zu. Weitere Informationen zu Cookies erhalten Sie in unserer Datenschutzerklärung. OK