Vergleichsoperator in Variable speichern

Frezl

Erfahrenes Mitglied
Hey Ihr!

Der Titel ist vll etwas missverständlich, aber so könnte die Lösung meines Problems aussehen.

Ich habe eine Funktion geschrieben, die aus einem riesigen zweidimensionalen Array (= Tabelle) die für meinen Zweck nötigen Zeilen und Spalten ausliest und wiederum als Array zurückgibt. Das funktioniert soweit schon super, aber jetzt möchte ich, dass ich diese Filterregeln als Parameter an die Funktion an übergeben kann. Das ganze sollte dann so funktionieren:

PHP:
array filterArray(array $table, array $filterCols, array $filterRows)

Die Spalten sind kein Problem, da ich da einfach nach Spaltennummern such. Es wird also ein Array übergeben, das Zahlen enthält.

Bei den Zeilen möchte ich aber z.B. alle die rausfiltern, bei denen der Inhalt der Spalte mit dem Index 1 ungleich 'Yes' ist. Wie kann ich diese Filterregel in ein Array packen? Ich hatte mir das in etwa so vorgestellt:

PHP:
//                  Key => array(Field, Operation, Value)
$filterRows = array(  0 => array(1, '!=', 'Yes')
                      1 => array(5, '=',  'de')  );

Ganz so einfach funktionierts leider nicht :-( Kann mir bitte jemand nen Tipp geben, wie es funktionieren könnte?

Gruß und Dank, Frezl
 
Zuletzt bearbeitet:
Ich würde eine Row-Class (Entity) machen. Darin kannst du dann die kompliziertesen Abhängigkeiten ausprogrammieren.
Am Schluss hast du ein Array mit Objekten deiner Row-Class
 
Hey yaslaw,

danke für deine schnelle Antwort! Kannst du mir vll ein Beispiel geben, wie du das meinst. Ich kanns mir grad net so genau vorstellen...

Gruß und Dank, Frezl
 
Machst eine Classe für die Row mit dem Filter und allen speziefischen Funktionen.
Die ExtendedArrayObject ist wieter unten aufgeführt. Sie nimmt die ale __Set etc ab, damit du nicht jedes Feld einzeln ausprorgammieren musst
PHP:
class MyRow extends ExtendedArrayObject{
    public function filter($field){
        return ($this->$field == 11);
    }
}

Pro Row ein Objekt anlegen und abfüllen. Wie du das machst, ist dir überlassen. Hier einige möglichkeiten inkl. einer Auswertung mit dem Filter
PHP:
$row1 = new MyRow();
$row1->addVars(array('k1' => 11, 'k2' => 12));

$row2 = new MyRow();
$row2->k1 = 12;
$row2->k2 = 22;

$row3 = new MyRow();
$row3->addVars(array('k1' => 11, 'k2' => 23));

$table = array($row1, $row2, $row3);

foreach ($table as $row){
    if ($row->filter('k1')){
        echo "k1 " . $row->k1 . "<br />";
    }
}

Nun noch die ExtendedArrayObject. Die kannst du übernehmen.
PHP:
/**
* @copyright    mpl by ERB software
*               All rights reserved
* @author       stefan.erb@erb-software.com
*/
class ExtendedArrayObject extends ArrayObject implements ArrayAccess{
    public $__CHIELD__ = __CLASS__;

    /**
    * @return   Array
    * @access   public
    */
    public function toArray(){return $this->getArrayCopy();}

    /**
    * extract the array in this object
    * @access   public
    * @param    array<Variant>     extract the array to object properties
    */
    public function extract($object){
        if(is_a($object, 'ExtendedClass')){
            $this->exchangeArray($object->toArray());
        } elseif(is_array($object)){
            $this->exchangeArray($array);
        }
    }
    /**
    * add all variables form a array to this object
    * @param    array or ArrayObject
    * @access   public
    */
    public function addVarsRecursive($array){
        if(is_array($array)){
            $array = $array + $this->getArrayCopy();
        } elseif(is_a($array, 'ArrayObject')){
            $array = $array->getArrayCopy() + $this->getArrayCopy();
        }
        $this->exchangeArray($array);
    }
    
    /**
    * add all variables form a array to this object
    * @param    array or ArrayObject
    * @access   public
    */
    public function addVars($array){
        if(is_array($array)){
            $this->exchangeArray(array_merge($this->getArrayCopy(), $array));
        } elseif(is_a($array, 'ArrayObject')){
            $this->exchangeArray(array_merge($this->getArrayCopy(), $array->getArrayCopy()));
        }
    }

    /**
    * set
    * Magic Function __set for all properties
    * @access   public
    * @param    String name
    * @param    Variant vlaue
    */
    public function __set($name, $value){$this[$name] = $value;}

    /**
    * get
    * Magic Function __get for all properties
    * @access   public
    * @param    String name
    * @return   Variant value
    */
    public function __get($name){return $this[$name];}

    /**
    * __isset
    * @access   public
    * Magic Function __isset for all properties
    * @param    String name
    * @return   Boolean
    */
    public function __isset($name){$this->offsetExists($name);}

    /**
    * __unset
    * Magic Function __unset for all properties
    * @access   public
    * @param    String name
    */
    public function __unset($name){$this->offsetUnset($name);}

}

Das folgende File habe ich getestet und läuft. (all das von oben mal zum Test kombiniert)
PHP:
<?php
/**
* @copyright    mpl by ERB software
*               All rights reserved
* @author       stefan.erb@erb-software.com
*/
class ExtendedArrayObject extends ArrayObject implements ArrayAccess{
    public $__CHIELD__ = __CLASS__;

    /**
    * @return   Array
    * @access   public
    */
    public function toArray(){return $this->getArrayCopy();}

    /**
    * extract the array in this object
    * @access   public
    * @param    array<Variant>     extract the array to object properties
    */
    public function extract($object){
        if(is_a($object, 'ExtendedClass')){
            $this->exchangeArray($object->toArray());
        } elseif(is_array($object)){
            $this->exchangeArray($array);
        }
    }
    /**
    * add all variables form a array to this object
    * @param    array or ArrayObject
    * @access   public
    */
    public function addVarsRecursive($array){
        if(is_array($array)){
            $array = $array + $this->getArrayCopy();
        } elseif(is_a($array, 'ArrayObject')){
            $array = $array->getArrayCopy() + $this->getArrayCopy();
        }
        $this->exchangeArray($array);
    }
    
    /**
    * add all variables form a array to this object
    * @param    array or ArrayObject
    * @access   public
    */
    public function addVars($array){
        if(is_array($array)){
            $this->exchangeArray(array_merge($this->getArrayCopy(), $array));
        } elseif(is_a($array, 'ArrayObject')){
            $this->exchangeArray(array_merge($this->getArrayCopy(), $array->getArrayCopy()));
        }
    }

    /**
    * set
    * Magic Function __set for all properties
    * @access   public
    * @param    String name
    * @param    Variant vlaue
    */
    public function __set($name, $value){$this[$name] = $value;}

    /**
    * get
    * Magic Function __get for all properties
    * @access   public
    * @param    String name
    * @return   Variant value
    */
    public function __get($name){return $this[$name];}

    /**
    * __isset
    * @access   public
    * Magic Function __isset for all properties
    * @param    String name
    * @return   Boolean
    */
    public function __isset($name){$this->offsetExists($name);}

    /**
    * __unset
    * Magic Function __unset for all properties
    * @access   public
    * @param    String name
    */
    public function __unset($name){$this->offsetUnset($name);}

}

class MyRow extends ExtendedArrayObject{
    public function filter($field){
        return ($this->$field == 11);
    }
}

$row1 = new MyRow();
$row1->addVars(array('k1' => 11, 'k2' => 12));

$row2 = new MyRow();
$row2->k1 = 12;
$row2->k2 = 22;

$row3 = new MyRow();
$row3->addVars(array('k1' => 11, 'k2' => 23));

$table = array($row1, $row2, $row3);

foreach ($table as $row){
    if ($row->filter('k1')){
        echo "k1 " . $row->k1 . "<br />";
    }
}
?>
 
Wow, ganz schön viel Code :-O Ich habs ehrlich gesagt nicht so ganz durchstiegen. Vor der OOP hab ich mich in PHP bis jetzt immer gedrückt :-P Ist es mit deiner Methode auch möglich, Verknüpfungen zwischen zwei Regeln herzustellen? Also z.B.: "filtere alle Zeilen, ebi denen Spalte 0 == 'x' und Spalte 4 != 'y' ist"?

Ich habs in der Zwischenzeit so gelöst:
PHP:
/*
   * array filterArray(array $array, array $filterCols, array $filterRows)
   * 
   * Die Funktion filtert die benötigten Zeilen und Spalten aus einem zweidimensionalen Array heraus
   * und gibt diese wiederum in einem zweidimensionalen Array zurück. Die Filterregeln werden dabei,
   * für Spalten und Zeilen getrennt, wie folgt übergeben:
   * 
   * Spalten:
   * //            array (Id1, Id2, ..., Idn); 
   * $filterCols = array (0, 3, 4);   --> Es werden einfach die Indizes der benötigten Spalten angegeben
   * 
   * Reihen:
   * //            array  ( RegelId => array (SpaltenId, Operator, Wert) );   
   * $filterRows = array  ( 0 => array (0, '==', 'test'),
   *                        1 => array (3, '!=', 'xy')  );
   *                        
   * Leider sind damit keine UND-Verknüpfungen möglich :-(            
   */                                   
  function filterArray($array, $filterCols, $filterRows) {    
    // benötigte Zeilen kopieren
    $output_array = array();
    for($n = 0; $n < count($filterRows); $n++) {
      // Nach dem ersten Durchgang müssen vor jedem weiteren Durchgang die Arrays korrekt initialisiert werden.
      // Das output_array wird also mit jedem Durchgang schlanker, da mit jedem Durchgang eine Filterregel abgearbeitet
      // wird und damit Zeilen rausschmeißt. 
      if(count($output_array) > 0) {
        $array = $output_array;
        $output_array = array();
      }
      
      for($i = 0; $i < count($array); $i++) {
        switch($filterRows[$n][1]) {
          case '==':
            if($array[$i][$filterRows[$n][0]] == $filterRows[$n][2]) {
              array_push($output_array, $array[$i]);
            }
          break;
          case '!=':
            if($array[$i][$filterRows[$n][0]] != $filterRows[$n][2]) {
              array_push($output_array, $array[$i]);
            }    
          break;
          case '>':
            if($array[$i][$filterRows[$n][0]] > $filterRows[$n][2]) {
              array_push($output_array, $array[$i]);
            }
          
          break;
          case '>=':
            if($array[$i][$filterRows[$n][0]] >= $filterRows[$n][2]) {
              array_push($output_array, $array[$i]);
            }    
          break;
          case '<':
            if($array[$i][$filterRows[$n][0]] < $filterRows[$n][2]) {
              array_push($output_array, $array[$i]);
            }    
          break;
          case '<=':
            if($array[$i][$filterRows[$n][0]] <= $filterRows[$n][2]) {
              array_push($output_array, $array[$i]);
            }    
          break;
          default:
          
          break;
        }
      }
    }
  
    // benötigte Spalten kopieren
    $array = $output_array;
    $output_array = array();
    for($i = 0; $i < count($array); $i++) {
      $row = array();
      for($j = 0; $j < count($array[$i]); $j++) {
        if(in_array($j, $filterCols)) {
          array_push($row, $array[$i][$j]);
        }    
      }
      array_push($output_array, $row);
    }
    
    return $output_array;
  }

Mit dieser Methode sind solche Verknüpfungen leider nicht möglich,da das Array für jede Regel neu durchlaufen und jeweils das Ergebnis des letzten Filterdurchgangs verwendet wird. Außerdem gefällt mir nicht, dass es so viel ähnlicher Code ist :-P

Grüße, Frezl

// Edit: Ich seh grad, UND-Verknüpfungen sind doch möglich. Aber ODER-Verknüpfungen gehn leider net :-/ Man sollte irgendwie die ganze Boolesche Vergleichsoperation in eine Variable speichern können, also so:
PHP:
$filterRows = '0 == "test" || 0 == "abc"';
Im Prinzip so wie bei einer SQL-Abrfrage...
 
Zuletzt bearbeitet:
Ich würde mit den folgenden Befehlen eine Class bauen, die du auch mit einer statischen Funktion direkt auswerten kannst. Mit Eval() kannst du beliebige Vergleichsausdrücke umsetzen.

array_filter()
array_walk()
eval()


item: Die letzte Zeile zeigt den Aufruf wie du ihn haben willst (den statischen).
item: Wenn die Argumente mit Arrayelementen übergeben werden, wird jetzt ein OR daraus gemacht
item: die kompliziertere Formel für den Zeilenfilter siehst du bei der aufrufvariante 2
PHP:
<?php 

class MyFilter{
    private $filterRows;
    private $filterCols;
    
    /**
     * Statischer Aufruf der Classe als Funktion
     * @param array $array
     * @param array $filterRows
     * @param array $filterCols
     * @return array
     */
    public static function staticFilter($array, $filterRows, $filterCols){
        $me = new MyFilter($filterRows, $filterCols);
        return $me->filter($array);
    }
    
    /**
     * Constructor
     * @param array $filterRows
     * @param array $filterCols
     */
    public function __construct($filterRows = array(), $filterCols = array()){
        $this->filterRows = $filterRows;
        $this->filterCols = $filterCols;
    }
    
    /**
     * filterfunktion
     * @param array $array
     * @return array
     */
    public function filter($array){
        //Zeilen Filtern
        $array = array_filter($array, array($this, 'filterRow'));
        //Spalten filtern
        array_walk(&$array, array($this, 'filterCol'));
        return $array;
    }
   
    /**
     * setters
     */
    public function setFilterRows($array){
        $this->filterRows = $array;
    }
    public function setFilterCols($array){
        $this->filterCols = $array;
    }
    
    /**
     * Filter für die Zeilen
     * @param array $row
     * @return boolean
     */
    private function filterRow($row){
        foreach ($this->filterRows AS $filter){
            eval("\$eval = ({$filter});");
            if ($eval) return true;
        }
    }
    
    /**
     * Filter für die Spalten
     * @param $row
     * @return boolean
     */
    private function filterCol(&$row){
        for($i = count($row)-1; $i >=0; $i--){          
            if (!in_array($i, $this->filterCols)){
                
                array_splice($row, $i, 1); 
            }
        }   
    }  
}
//Datenarray
$array = array( array(1, 'No', 'de', 1),
                array(2, 'Yes', 'de', 2),
                array(3, 'Yes', 'ch', 3),
                array(4, 'No', 'ch', 4));
$filterRows = array("\$row[1] != 'Yes'", 
                    "\$row[2] == 'de'");
$filterCols = array(0,1,2);                

//Bsp 1:   Neuen Filter anlegen und auswerten                
$filter = new MyFilter($filterRows, $filterCols);
var_dump($filter->filter($array));
echo "<hr />";

// Bsp 2:Filtereigenschafte überschreiben
$filter->setFilterRows(array("\$row[1] != 'Yes' && \$row[2] == 'de'"));
$filter->setFilterCols(array(1,2));
var_dump($filter->filter($array));
echo "<hr />";

//Bsp 3: Statische Ausführung
var_dump(myFilter::staticFilter($array, $filterRows, $filterCols));
echo "<hr />";

?>
 
Zuletzt bearbeitet:
Zurück