PHP的array_map包括键

Jos*_*ino 179 php functional-programming

有没有办法做这样的事情:

$test_array = array("first_key" => "first_value", 
                    "second_key" => "second_value");

var_dump(array_map(function($a, $b) { return "$a loves $b"; }, 
         array_keys($test_array), 
         array_values($test_array)));
Run Code Online (Sandbox Code Playgroud)

但是,而不是调用,array_keysarray_values直接传递$test_array变量?

所需的输出是:

array(2) {
  [0]=>
  string(27) "first_key loves first_value"
  [1]=>
  string(29) "second_key loves second_value"
}
Run Code Online (Sandbox Code Playgroud)

eis*_*eis 179

不使用array_map,因为它不处理键.

array_walk做:

$test_array = array("first_key" => "first_value",
                    "second_key" => "second_value");
array_walk($test_array, function(&$a, $b) { $a = "$b loves $a"; });
var_dump($test_array);

// array(2) {
//   ["first_key"]=>
//   string(27) "first_key loves first_value"
//   ["second_key"]=>
//   string(29) "second_key loves second_value"
// }
Run Code Online (Sandbox Code Playgroud)

它确实改变了作为参数给出的数组,因此它不完全是函数式编程(因为你有像这样标记的问题).此外,正如注释中所指出的,这只会更改数组的值,因此键不会是您在问题中指定的键.

如果你愿意,你可以编写一个修复上面各点的函数,如下所示:

function mymapper($arrayparam, $valuecallback) {
  $resultarr = array();
  foreach ($arrayparam as $key => $value) {
    $resultarr[] = $valuecallback($key, $value);
  }
  return $resultarr;
}

$test_array = array("first_key" => "first_value",
                    "second_key" => "second_value");
$new_array = mymapper($test_array, function($a, $b) { return "$a loves $b"; });
var_dump($new_array);

// array(2) {
//   [0]=>
//   string(27) "first_key loves first_value"
//   [1]=>
//   string(29) "second_key loves second_value"
// }
Run Code Online (Sandbox Code Playgroud)

  • 这不是"函数式编程",因为`array_walk()`不返回结果数组,而是返回bool. (3认同)
  • 正确,已更改 :) 很高兴他们从 array_walk 制作了 array_map。 (2认同)

Kev*_*eal 125

这可能是最短且最容易推理的:

$states = array('az' => 'Arizona', 'al' => 'Alabama');

array_map(function ($short, $long) {
    return array(
        'short' => $short,
        'long'  => $long
    );
}, array_keys($states), $states);

// produces:
array(
     array('short' => 'az', 'long' => 'Arizona'), 
     array('short' => 'al', 'long' => 'Alabama')
)
Run Code Online (Sandbox Code Playgroud)

  • 我刚才意识到这个问题具体说不要使用`array_keys()`.但这似乎是一个愚蠢的要求. (11认同)
  • 这个问题提供了一个使用array_keys()的解决方案,提供一个在当前解决方案中没有优势(例如,调用较少函数)的答案是愚蠢的. (2认同)
  • 原始问题的答案是否定的,这是最合适的解决方案。 (2认同)
  • 该答案忽略了所问问题的示例数据和所需的输出。 (2认同)

Nic*_*nks 58

这是我非常简单的PHP 5.5兼容解决方案:

function array_map_assoc(callable $f, array $a) {
    return array_column(array_map($f, array_keys($a), $a), 1, 0);
}
Run Code Online (Sandbox Code Playgroud)

你提供的callable本身应该返回一个包含两个值的数组,即return [key, value].因此内部调用array_map产生一个数组数组.然后通过将其转换回单维数组array_column.

用法

$ordinals = [
    'first' => '1st',
    'second' => '2nd',
    'third' => '3rd',
];

$func = function ($k, $v) {
    return ['new ' . $k, 'new ' . $v];
};

var_dump(array_map_assoc($func, $ordinals));
Run Code Online (Sandbox Code Playgroud)

产量

array(3) {
  ["new first"]=>
  string(7) "new 1st"
  ["new second"]=>
  string(7) "new 2nd"
  ["new third"]=>
  string(7) "new 3rd"
}
Run Code Online (Sandbox Code Playgroud)

部分申请

如果您需要使用不同数组但相同映射函数多次使用该函数,您可以执行一些称为部分函数应用程序(与' currying ' 相关)的操作,它允许您仅在调用时传入数据数组:

function array_map_assoc_partial(callable $f) {
    return function (array $a) use ($f) {
        return array_column(array_map($f, array_keys($a), $a), 1, 0);
    };
}

...
$my_mapping = array_map_assoc_partial($func);
var_dump($my_mapping($ordinals));
Run Code Online (Sandbox Code Playgroud)

它产生相同的输出,给定$func并且$ordinals与之前一样.

注意:如果映射函数为两个不同的输入返回相同的键,则与后一个键关联的值将获胜.反转输入数组并输出结果array_map_assoc以允许早期键获胜.(我的示例中返回的键不会发生碰撞,因为它们包含源数组的键,而后者必须是唯一的.)


替代

以下是上述的变体,对某些人来说可能更合乎逻辑,但需要PHP 5.6:

function array_map_assoc(callable $f, array $a) {
    return array_merge(...array_map($f, array_keys($a), $a));
}
Run Code Online (Sandbox Code Playgroud)

在此变体中,您提供的函数(数据数据映射在其上)应该返回一行关联数组,即return [key => value].映射可调用的结果然后简单地解压缩并传递给array_merge.如前所述,返回重复键将导致后来的值获胜.

nb Alex83690在评论中指出,使用array_replace此处代替array_merge将保留整数键.array_replace不修改输入数组,因此对于功能代码是安全的.

如果您使用的是PHP 5.3到5.5,则以下内容是等效的.它使用array_reduce二进制+数组运算符将生成的二维数组转换为一维数组,同时保留键:

function array_map_assoc(callable $f, array $a) {
    return array_reduce(array_map($f, array_keys($a), $a), function (array $acc, array $a) {
        return $acc + $a;
    }, []);
}
Run Code Online (Sandbox Code Playgroud)

用法

因此可以使用这两种变体:

$ordinals = [
    'first' => '1st',
    'second' => '2nd',
    'third' => '3rd',
];

$func = function ($k, $v) {
    return ['new ' . $k => 'new ' . $v];
};

var_dump(array_map_assoc($func, $ordinals));
Run Code Online (Sandbox Code Playgroud)

注意=>而不是,in $func.

输出与之前相同,并且每个都可以以与以前相同的方式部分应用.


 摘要

原始问题的目标是使调用的调用尽可能简单,代价是调用更复杂的函数; 特别是,能够将数据数组作为单个参数传递,而无需拆分键和值.使用本答案开头提供的功能:

$test_array = ["first_key" => "first_value",
               "second_key" => "second_value"];

$array_map_assoc = function (callable $f, array $a) {
    return array_column(array_map($f, array_keys($a), $a), 1, 0);
};

$f = function ($key, $value) {
    return [$key, $key . ' loves ' . $value];
};

var_dump(array_values($array_map_assoc($f, $test_array)));
Run Code Online (Sandbox Code Playgroud)

或者,仅针对此问题,我们可以简化array_map_assoc()输出键的功能,因为问题不会要求它们:

$test_array = ["first_key" => "first_value",
               "second_key" => "second_value"];

$array_map_assoc = function (callable $f, array $a) {
    return array_map($f, array_keys($a), $a);
};

$f = function ($key, $value) {
    return $key . ' loves ' . $value;
};

var_dump($array_map_assoc($f, $test_array));
Run Code Online (Sandbox Code Playgroud)

所以答案是否定的,你无法避免调用array_keys,但你可以抽象出array_keys被调用到更高阶函数的地方,这可能已经足够了.

  • 似乎这应该被标记为正确的答案. (7认同)
  • 谢谢@eddiewould,但我已经晚了4年半了:)我来到这里寻找解决方案,找不到我喜欢的,所以想出了我自己的. (6认同)
  • 我会是那个人。PHP 5.3 不再是 *this* 答案的日期的要求。恕我直言。 (4认同)
  • 您的第一个替代解决方案无效。您必须用 `array_replace` 替换 `array_merge` 以保留将是整数的键。 (2认同)
  • 如果有人对保留键的数组映射函数感兴趣,同时它的回调可以访问键和值,并且可以仅返回一个值(如普通映射函数所做的那样)而不是“特殊格式化”值(关联数组)一行),然后这里是稍微修改的 php 5.6 解决方案: `function array_map_assoc(callable $f, array $a) { return array_merge(...array_map(function ($k, $v) use ($f) { return [ $k => $f($k, $v) ]; }, array_keys($a), $a)); }`。为此,“$f”必须用另一个函数包装,该函数将新值映射到“[key=>new_value]”。 (2认同)

Tad*_*kas 20

使用PHP5.3或更高版本:

$test_array = array("first_key" => "first_value", 
                    "second_key" => "second_value");

var_dump(
    array_map(
        function($key) use ($test_array) { return "$key loves ${test_array[$key]}"; },
        array_keys($test_array)
    )
);
Run Code Online (Sandbox Code Playgroud)

  • 我认为要求是“而不是调用array_keys和array_values,直接传递$test_array变量”,这可以在没有array_keys的情况下使用吗? (3认同)

Ost*_*PHP 14

$array = [
  'category1' => 'first category',
  'category2' => 'second category',
];
 
$new = array_map(function($key, $value) {
  return "{$key} => {$value}";
}, array_keys($array), $array);
Run Code Online (Sandbox Code Playgroud)


Ian*_*anS 5

看这里!有一个简单的解决方案!

function array_map2(callable $f, array $a)
{
    return array_map($f, array_keys($a), $a);
}
Run Code Online (Sandbox Code Playgroud)

正如问题中所述,array_map 已经完全具备所需的功能。这里的其他答案严重使事情过于复杂:array_walk不起作用。

用法

正如您对示例所期望的那样:

$test_array = array("first_key" => "first_value", 
                    "second_key" => "second_value");

var_dump(array_map2(function($a, $b) { return "$a loves $b"; }, $test_array));
Run Code Online (Sandbox Code Playgroud)

  • 其他答案使事情变得过于复杂,因为指定的问题“qrrqy_keys()”不应该用于#reasons (2认同)

Fra*_*.M. 5

我将使用 5.6 或更高版本为该问题添加另一个解决方案。不知道它是否比已经很好的解决方案更有效(可能不是),但对我来说它更容易阅读:

$myArray = [
    "key0" => 0,
    "key1" => 1,
    "key2" => 2
];

array_combine(
    array_keys($myArray),
    array_map(
        function ($intVal) {
            return strval($intVal);
        },
        $myArray
    )
);
Run Code Online (Sandbox Code Playgroud)

在 中strval()用作示例函数array_map,这将生成:

array(3) {
  ["key0"]=>
  string(1) "0"
  ["key1"]=>
  string(1) "1"
  ["key2"]=>
  string(1) "2"
}
Run Code Online (Sandbox Code Playgroud)

希望我不是唯一一个觉得这很容易掌握的人。 从一个键数组和一个值数组array_combine创建一个key => value数组,其余的都是不言自明的。