代码之家  ›  专栏  ›  技术社区  ›  quantumSoup

在PHP中模拟Ruby的inject()行为

  •  3
  • quantumSoup  · 技术社区  · 15 年前

    从这个问题 here ,我编写了一个枚举包装器,使其具有一些可以与lambda一起使用的方法,以便在一定程度上模拟Ruby对枚举中块的使用。

    class enum {
        public $arr;
    
        function __construct($array) {
            $this->arr = $array;
        }
    
        function each($lambda) {
            array_walk($this->arr, $lambda);
        }
    
        function find_all($lambda) {
            return array_filter($this->arr, $lambda);
        }
    
        function inject($lambda, $initial=null) { 
            if ($initial == null) { 
                $first = array_shift($this->arr); 
                $result = array_reduce($this->arr, $lambda, $first); 
                array_unshift($this->arr, $first); 
    
                return $result; 
            } else { 
                return array_reduce($this->arr, $lambda, $initial); 
            } 
        } 
    
    }
    
    
    $list = new enum(array(-1, 3, 4, 5, -7));
    $list->each(function($a) { print $a . "\n";});
    
    // in PHP you can also assign a closure to a variable 
    $pos = function($a) { return ($a < 0) ? false : true;};
    $positives = $list->find_all($pos);
    

    现在,我如何实现 inject() 尽可能优雅?


    编辑: 方法实现如上所示。使用实例:

    // inject() examples 
    $list = new enum(range(5, 10)); 
    
    $sum = $list->inject(function($sum, $n) { return $sum+$n; }); 
    $product = $list->inject(function($acc, $n) { return $acc*$n; }, 1); 
    
    $list = new enum(array('cat', 'sheep', 'bear')); 
    $longest = $list->inject(function($memo, $word) { 
            return (strlen($memo) > strlen($word)) ? $memo : $word; } 
        ); 
    
    1 回复  |  直到 15 年前
        1
  •  5
  •   Artefacto    15 年前

    我对Ruby不熟悉,但从描述上看,它似乎与 array_reduce .

    mixed array_reduce ( array $input , callback $function [, mixed $initial = NULL ] )

    array_reduce() 将函数函数迭代应用于数组输入的元素,以便将数组减少到单个值。

    除了“减少”,这种操作有时也被称为 "fold" ;在Mathematica中:

    Fold[f, init, {a, b, c, d}] == f[f[f[f[init, a], b], c], d]
    

    第二个表单使用集合的第一个元素作为初始值(并在迭代时跳过该元素)。

    第二种形式可以这样实现:

    //$arr is the initial array
    $first = array_shift($arr);
    $result = array_reduce($arr, $callback, $first);
    

    对姆亚丁的回应

    PHP中的数组函数不能这样使用,因为它们只能用于数组,而不能用于任意对象。

    这里有几个选项:

    • 在将对象传递给 排列减少 . 实际上,这并没有多大价值,因为转换包括创建一个数组,其中对象属性作为元素。只能在内部更改此行为(写入本机扩展)。
    • 您可以让所有对象实现一个方法接口 toArray 必须先打电话才能把它传给 排列减少 . 也不是什么好主意。
    • 您可以实现的版本 排列减少 与任何 Traversable 对象。这很容易,但你不能 可穿越的 在函数声明中键入提示,因为数组不是对象。有了这样的提示,每个数组都必须封装在 ArrayIterator 函数调用之前的对象。