PHP: Can I get the index in an array_map function?

后端 未结 5 1962
甜味超标
甜味超标 2021-01-30 09:57

I\'m using a map in php like so:

function func($v) {
    return $v * 2;
}

$values = array(4, 6, 3);
$mapped = array_map(func, $values);
var_dump($mapped);


        
相关标签:
5条回答
  • 2021-01-30 10:24

    For a fast and open solution (without doubling array using array_keys and similar):

    /**
     * Array map alternative to work with values and keys of single array.
     *
     * Callable receives $value and $index of $sourceArray as arguments
     * If keys are not preserved via $preserveKeys - $keyCallback can be used to determinate key
     *
     * @param array $sourceArray
     * @param callable|null $valueCallback
     * @param callable|null $keyCallback
     * @param bool $preserveKeys
     * @return array
     */
    function array_map_indexed(
        array $sourceArray,
        ?callable $valueCallback = null,
        ?callable $keyCallback = null,
        bool $preserveKeys = true
    ): array {
        $newArray = [];
    
        foreach ($sourceArray as $key => $value) {
            if ($preserveKeys) {
                $newArray[$keyCallback ? $keyCallback($value, $key) : $key] = $valueCallback
                    ? $valueCallback($value, $key)
                    : $value;
            } else {
                $newArray[] = $valueCallback
                    ? $valueCallback($value, $key)
                    : $value;
            }
        }
    
        return $newArray;
    }
    

    Usage examples:

    $result = array_map_indexed(
        [
            'a' => 'aValue',
            'b' => 'bValue',
        ],
        function($value, $index) {
            return [$value, $index];
        },
    );
    //Array ( [a] => Array ( [0] => aValue [1] => a ) [b] => Array ( [0] => bValue [1] => b ) )
    
    $result = array_map_indexed(
        [
            'a' => 'aValue',
            'b' => 'bValue',
        ],
        function($value, $index) {
            return $index.$value;
        },
        null,
        false
    );
    //Array ( [0] => aaValue [1] => bbValue )
    
    $result = array_map_indexed(
        [
            'a' => 'aValue',
            'b' => 'bValue',
        ],
        null,
        function($value, $index) {
            return $value === 'aValue' ? 'specificKey' : $index;
        },
    );
    //Array ( [specificKey] => aValue [b] => bValue )
    
    0 讨论(0)
  • 2021-01-30 10:43

    Very simple:

    Only array_map fuction: does not have index key!

     $params = [4,6,2,11,20];
    
     $data = array_map(function($v) { return ":id{$v}";}, $params);
    
     array (size=5)
      0 => string ':id4' (length=4)
      1 => string ':id6' (length=4)
      2 => string ':id2' (length=4)
      3 => string ':id11' (length=5)
      4 => string ':id20' (length=5)
    

    Now, combine with array_keys:

    $data = array_map(
        function($k) use ($params) { return ":id{$k}_${params[$k]}"; },
        array_keys($params)
     );
    
    array (size=5)
      0 => string ':id0_4' (length=6)
      1 => string ':id1_6' (length=6)
      2 => string ':id2_2' (length=6)
      3 => string ':id3_11' (length=7)
      4 => string ':id4_20' (length=7)
    
    0 讨论(0)
  • 2021-01-30 10:47

    You can create your own map function using foreach:

    <?php
    
    function myCallback($key, $val)
    {
        var_dump("myCallback - key: $key, val: $val");
        return $val * 2;
    }
    
    function foreachMap($callback, $givenArray) {
        $result = [];
        foreach ($givenArray as $key=>$val) {
            $result[$key] = $callback($key, $val);
        }
        return $result;
    }
    
    $values = array(4, 6, 3);
    $mapped = foreachMap('myCallback', $values);
    var_dump($mapped);
    
    

    try: https://3v4l.org/pmFlB

    0 讨论(0)
  • 2021-01-30 10:48

    Sure you can, with the help of array_keys():

    function func($v, $k)
    {
        // key is now $k
        return $v * 2;
    }
    
    $values = array(4, 6, 3);
    $mapped = array_map('func', $values, array_keys($values));
    var_dump($mapped);
    
    0 讨论(0)
  • 2021-01-30 10:48

    When mapping an anonymous function over an anonymous array, there is no way to access the keys:

    array_map(
        function($val) use ($foo) { /* ... */ },
        array(key1 => val1,
              key2 => val2,
              /* ... */));
    

    array_reduce doesn't get access to the keys either. array_walk can access keys, but the array is passed by reference, which requires a layer of indirection.

    Some solutions are:

    Array of pairs

    This is bad, since we're changing the original array. Plus the boilerplate "array()" calls increase linearly with the length of the array:

    array_map(
        function($pair) use ($foo) {
            list($key, $val) = $pair;
            /* ... */
        },
        array(array(key1, val1),
              array(key2, val2),
              /* ... */));
    

    Temporary variable

    We're acting on the original array, and the boilerplate is constant, but we can easily clobber an existing variable:

    $i_hope_this_does_not_conflict = array(key1 => val1,
                                           key2 => val2,
                                           /* ... */);
    array_map(
        function($key, $val) use ($foo) { /* ... */ },
        array_keys($i_hope_this_does_not_conflict),
        $i_hope_this_does_not_conflict);
    unset($i_hope_this_does_not_conflict);
    

    One-shot function

    We can use function scope to prevent clobbering existing names, but have to add an extra layer of "use":

    call_user_func(
        function($arr) use ($foo) {
            return array_map(function($key, $val) use ($foo) { /* ... */ },
                             array_keys($arr),
                             $arr);
        },
        array(key1 => val1,
              key2 => val2,
              /* ... */));
    

    Multi-argument one-shot function

    We define the function we're mapping in the original scope to prevent the "use" boilerplate):

    call_user_func(
        function($f, $arr) {
            return array_map($f, array_keys($arr), $arr);
        },
        function($key, $val) use ($foo) { /* ... */ },
        array(key1 => val1,
              key2 => val2,
              /* ... */));
    

    New function

    The interesting thing to note is that our last one-shot function has a nice, generic signature and looks a lot like array_map. We might want to give this a name and re-use it:

    function array_mapk($f, $arr) {
        return array_map($f, array_keys($arr), $arr);
    }
    

    Our application code then becomes:

    array_mapk(
        function($key, $val) use ($foo) { /* ... */ },
        array(key1 => val1,
              key2 => val2,
              /* ... */));
    

    Indirect Array Walk

    When writing the above I'd ignored array_walk since it requires its argument to be passed by reference; however, I've since realised that it's easy to work around this using call_user_func. I think this is the best version so far:

    call_user_func(
        'array_walk',
        array(key1 => val1,
              key2 => val2,
              /* ... */),
        function($val, $key) use ($foo) { /* ... */ });
    
    0 讨论(0)
提交回复
热议问题