2016-11-28 181 views
0

我有阵列过滤多维数组

$rows = [ 
    ['k'=>1, 'dop1'=>'take', 'dop2' => 'a', 'dat' => '25-11-2016'], 
    ['k'=>2, 'dop1'=>'make', 'dop2' => 'b', 'dat' => '26-11-2016'], 
    ['k'=>3, 'dop1'=>'sake', 'dop2' => 'c', 'dat' => '27-11-2016'], 
    ['k'=>4, 'dop1'=>'bake', 'dop2' => 'd', 'dat' => '28-11-2016'], 
    ['k'=>5, 'dop1'=>'dake', 'dop2' => 'e', 'dat' => '29-11-2016'], 
    ['k'=>6, 'dop1'=>'jake', 'dop2' => 'f', 'dat' => '30-11-2016'], 
    ['k'=>7, 'dop1'=>'ake', 'dop2' => 'g', 'dat' => '24-11-2016'] 
]; 

和另一个数组用于过滤

$filters = [ 
    ['dat', '=', '27-11-2016'], 
    ['dop1', '=', "bake"], 
    ['dop1', '=', "sake"], 
    ['dop1', '=', "take"], 
]; 

如果重复阵列滤光器的第一个元素,将它们之间OR表达,否则将是AND表达式。 所以这里的结果必须是['k'=>3, 'dop1'=>'sake', 'dop2' => 'c', 'dat' => '27-11-2016'],因为'dat' => '27-11-2016'存在于filters数组中,并且'dop1'=>'sake''dop1'=>'sake'也存在。你能帮我吗?

UPDATE 这是我的代码示例,但在注释的位置存在问题。

$dop = ['dop1', 'dop2', 'dop3', 'dop4']; 
$result = []; 

foreach ($rows as $row) { 
    foreach ($filters as $filter) { 
     if(in_array($filter[0], $dop)){ 
      $new_filter = []; 
      $f = explode("\n", $filter[2]); 
      foreach ($f as $item) { 
       array_push($new_filter, [$filter[0], $filter[1], $item]); 
      } 


      if(count($result) == 0){ 
       foreach ($new_filter as $new) { 
        if($row[$new[0]] == $new[2]){ 
         array_push($result, ['r' => $row, 'filter' => $new, 'validity' => 'valid']); 
        } 
       } 
      } else { 
       foreach ($new_filter as $new) { 
        for($i=0;$i<count($result);$i++){ 
         if($result[$i]['filter'][0] == $new[0] && $result[$i]['filter'][1] == $new[1] && $result[$i]['filter'][2] != $new[2]){ 
          //array_push($result, ['r' => $row, 'filter' => $new, 'validity' => 'valid']); 
         } 
        } 
       } 
       $invalid = 1; 
       $id = 0; 
       foreach ($new_filter as $new) { 
        for($i=0;$i<count($result);$i++){ 
         if($result[$i]['r'][$new[0]] == $new[2]){ 
          $invalid = 0; 
          $id = $i; 
          break 2; 
         } 
        } 
       } 
       if($invalid == 1){ 
        $result[$id]['validity'] = 'invalid'; 
       } 
      } 
     } elseif($filter[0] == 'dat') { 
      if(count($result) == 0){ 
       if($row[$filter[0]] == $filter[2]){ 
        array_push($result, ['r' => $row, 'filter' => $filter, 'validity' => 'valid']); 
       } 
      } else { 
       if($row[$filter[0]] == $filter[2]){ 
        for($i=0;$i<count($result);$i++){ 
         if($result[$i]['r'][$filter[0]] != $filter[2]){ 
          $result[$i]['validity'] = 'invalid'; 
         } 
        } 
       } 
      } 
     } 
    } 
} 
$c = 0; 
foreach ($result as $r) { 
    if($r['validity'] == 'valid'){ 
     $c++; 
    } 
} 
echo $c; 
+0

你可以再试一次来说明OR和AND部分......我不完全相信我明白了。你的例子预期的结果是好的......但请澄清当你是或当你是和。 – WEBjuju

+1

我不能发现你自己的尝试,所以你自己的代码来实现这一点。你如何期待我们帮助?请注意,我们在这里帮助您编写代码,而不是为您编写代码。为此,请聘请付费程序员。 – arkascha

+0

@arkascha抱歉,忘记了我自己的代码,我更新了问题,请帮助我。 –

回答

0

做了一些工作给你的不好的事情是我的方式需要一个eval这可能是危险的,这取决于你将在值中的字符串...

$rows = [ 
    ['k'=>1, 'dop1'=>'take', 'dop2' => 'a', 'dat' => '25-11-2016'], 
    ['k'=>2, 'dop1'=>'make', 'dop2' => 'b', 'dat' => '26-11-2016'], 
    ['k'=>3, 'dop1'=>'sake', 'dop2' => 'c', 'dat' => '27-11-2016'], 
    ['k'=>4, 'dop1'=>'bake', 'dop2' => 'd', 'dat' => '28-11-2016'], 
    ['k'=>5, 'dop1'=>'dake', 'dop2' => 'e', 'dat' => '29-11-2016'], 
    ['k'=>6, 'dop1'=>'jake', 'dop2' => 'f', 'dat' => '30-11-2016'], 
    ['k'=>7, 'dop1'=>'ake', 'dop2' => 'g', 'dat' => '24-11-2016'] 
]; 

$filters = [ 
    ['dat', '=', '27-11-2016'], 
    ['dop1', '=', "bake"], 
    ['dop1', '=', "sake"], 
    ['dop1', '=', "take"], 
]; 


function marrfilter($filters_arr, $rows) 
{ 
    /* 
    * Building filters to eval 
    */ 
    $buildFilter = function($key, $op, $val) 
    { 
     switch($op) 
     { 
      case '=': 
       $op = '=='; 
       break; 
      case '==': 
      case '===': 
      case '!=': 
      case '!==': 
      case '>': 
      case '>=': 
      case '<': 
      case '<=': 
       break; 

      default: 
       throw new Exception('Unknown operand'); 
     } 

     $val = addslashes($val); 

     return '$val ' . $op . " '" . $val . "'"; 
    }; 

    $filters = array(); 
    foreach($filters_arr as $k => $v) 
    { 
     list($key, $op, $val) = $v; 

     if(!isset($filters[$key])) 
     { 
      $filters[$key] = $buildFilter($key, $op, $val); 
     } 
     else 
     { 
      if(!is_array($filters[$key])) 
      { 
       $filters[$key] = array($filters[$key]); 
      } 

      $filters[$key][] = $buildFilter($key, $op, $val); 
     } 
    } 

    /* 
    * Filter function 
    */ 
    $applyFilter = function($row, $fk, $fv) 
    { 
     if(!array_key_exists($fk, $row)) 
     { 
      return false; 
     } 

     $val = $row[$fk]; 

     if(is_array($fv)) 
     { 
      $test = false; 
      foreach($fv as $ft) 
      { 
       eval('$test = (' . $ft . ');'); 

       if($test) return true; 
      } 

      return false; 
     } 
     else 
     { 
      $test = false; 
      // thats why you realy have to care about what you put in filters and data :) 
      eval('$test = (' . $fv . ');'); 

      if($test) return true; 
     } 

     return false; 
    }; 

    /* 
    * Filtering 
    */ 
    $result = array(); 
    foreach($rows as $row) 
    { 
     $r = array(); 
     foreach($filters as $fk => $fv) 
     { 
      $r[] = $applyFilter($row, $fk, $fv); 
     } 

     $r = array_filter($r); 

     if(count($r) == count($filters)) 
     { 
      $result[] = $row; 
     } 
    } 

    return $result; 
} 

这里工作很好。

见在线:http://sandbox.onlinephpfunctions.com/code/185658700006fe913e6592a7fc51d4cce0db6a68所有的

首先我建立的过滤器,我可以使用,那么我将它应用到所有行的数组。就这么简单:对

希望它能帮助:)


编辑:

重建功能的一些低劣的部分,除去eval防止真棒安全隐患。

  • 现在buildFilter返回函数返回一个简单的测试,这取决于您设置哪些运算 (你甚至可以自定义测试呵呵)
  • ApplyFilter修改结果:)

这是新的代码

$rows = [ 
    ['k'=>1, 'dop1'=>'take', 'dop2' => 'a', 'dat' => '25-11-2016'], 
    ['k'=>2, 'dop1'=>'make', 'dop2' => 'b', 'dat' => '26-11-2016'], 
    ['k'=>3, 'dop1'=>'sake', 'dop2' => 'c', 'dat' => '27-11-2016'], 
    ['k'=>4, 'dop1'=>'bake', 'dop2' => 'd', 'dat' => '28-11-2016'], 
    ['k'=>5, 'dop1'=>'dake', 'dop2' => 'e', 'dat' => '29-11-2016'], 
    ['k'=>6, 'dop1'=>'jake', 'dop2' => 'f', 'dat' => '30-11-2016'], 
    ['k'=>7, 'dop1'=>'ake', 'dop2' => 'g', 'dat' => '24-11-2016'] 
]; 

$filters = [ 
    ['dat', '=', '27-11-2016'], 
    ['dop1', '=', "bake"], 
    ['dop1', '=', "sake"], 
    ['dop1', '=', "take"], 
]; 


function marrfilter($filters_arr, $rows) 
{ 
    /* 
    * Building filters to eval 
    */ 
    $buildFilter = function($op, $val) 
    { 
     return function($data) use ($val, $op) 
     { 
      switch($op) 
      { 
       case '=': 
       case '==': 
        return ($data == $val); 
       case '===': 
        return ($data === $val); 

       case '!=': 
        return ($data != $val); 
       case '!==': 
        return ($data !== $val); 

       case '>': 
        return ($data > $val); 
       case '>=': 
        return ($data >= $val); 

       case '<': 
        return ($data < $val); 
       case '<=': 
        return ($data <= $val); 

       default: 
        throw new Exception('Unknown operand ' . $op); 
      } 
     }; 
    }; 

    $filters = array(); 
    foreach($filters_arr as $k => $v) 
    { 
     list($key, $op, $val) = $v; 

     if(!isset($filters[$key])) 
     { 
      $filters[$key] = $buildFilter($op, $val); 
     } 
     else 
     { 
      if(!is_array($filters[$key])) 
      { 
       $filters[$key] = array($filters[$key]); 
      } 

      $filters[$key][] = $buildFilter($op, $val); 
     } 
    } 

    /* 
    * Filter function 
    */ 
    $applyFilter = function($row, $fk, $fv) 
    { 
     // Key not found in row 
     if(!array_key_exists($fk, $row)) 
     { 
      return false; 
     } 

     // Get row[key] value 
     $val = $row[$fk]; 

     // if we have multiple tests for the filter it's an OR 
     if(is_array($fv)) 
     { 
      foreach($fv as $ft) 
      { 
       if($ft($val) === true) return true; // return true if filter passed 

       // or continue if not 
      } 
     } 
     else 
     { 
      if($fv($val) === true) return true; // return true if filter passed 
     } 

     // if no filter passed, return false 
     return false; 
    }; 

    /* 
    * Filtering 
    */ 
    $result = array(); 
    foreach($rows as $row) 
    { 
     $r = array(); 
     foreach($filters as $fk => $fv) 
     { 
      $r[] = $applyFilter($row, $fk, $fv); 
     } 

     $r = array_filter($r); 

     if(count($r) == count($filters)) 
     { 
      $result[] = $row; 
     } 
    } 

    return $result; 
} 
+0

请仅作为一个例子,这是不可靠的找到这个代码在生产中,花了10分钟来建立它... – Bobot

+0

很酷,谢谢。明天,我会测试(我有很多测试版本)并将其修改为生产。非常感谢。 –

0

所以无需编写代码给你,看看PHP's array_filter()

的伪代码,你需要看起来像这样的内容:

var_dump(array_filter($rows, function($row) { 
    global $filtered; 

    $match = 0; 

    foreach ($filtered as $index=>$filter) { 
    // run code here to determine if this is an OR or AND and apply matching to the $row 
    // $row will be like ['k'=>1, 'dop1'=>'take', 'dop2' => 'a', 'dat' => '25-11-2016'], 
    // match based on the index of your $filtered ($index===0 AND, otherwise OR) 
    } 

    return $match; 
});