PHP';s数组_映射,包括键

PHP';s数组_映射,包括键,php,functional-programming,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_

有没有办法做到这一点:

$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)));
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"
// }
但是不是调用
array\u键
array\u值
,而是直接传递
$test\u数组
变量

所需输出为:

array(2) {
  [0]=>
  string(27) "first_key loves first_value"
  [1]=>
  string(29) "second_key loves second_value"
}
我所说的“手动循环”是指编写一个使用
foreach
的自定义函数。这将返回一个新数组,如
array\u map
那样,因为函数的作用域导致
$array
是一个副本而不是引用:

function map($array, callable $fn) {
  foreach ($array as $k => &$v) $v = call_user_func($fn, $k, $v);
  return $array;
}
您将
array\u map
array\u键一起使用的技术实际上看起来更简单、更强大,因为您可以使用
null
作为回调来返回键值对:

function map($array, callable $fn = null) {
  return array_map($fn, array_keys($array), $array);
}

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

是否:

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

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

$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)));
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"
// }
基于,以下是我为避免弄乱原始阵列而最终采取的措施:

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

$result_array = array();
array_walk($test_array, 
           function($a, $b) use (&$result_array) 
           { $result_array[] = "$b loves $a"; }, 
           $result_array);
var_dump($result_array);

我发现它缺少一个显而易见的答案:

function array_map_assoc(){
    if(func_num_args() < 2) throw new \BadFuncionCallException('Missing parameters');

    $args = func_get_args();
    $callback = $args[0];

    if(!is_callable($callback)) throw new \InvalidArgumentException('First parameter musst be callable');

    $arrays = array_slice($args, 1);

    array_walk($arrays, function(&$a){
        $a = (array)$a;
        reset($a);
    });

    $results = array();
    $max_length = max(array_map('count', $arrays));

    $arrays = array_map(function($pole) use ($max_length){
        return array_pad($pole, $max_length, null);
    }, $arrays);

    for($i=0; $i < $max_length; $i++){
        $elements = array();
        foreach($arrays as &$v){
            $elements[] = each($v);
        }
        unset($v);

        $out = call_user_func_array($callback, $elements);

        if($out === null) continue;

        $val = isset($out[1]) ? $out[1] : null;

        if(isset($out[0])){
            $results[$out[0]] = $val;
        }else{
            $results[] = $val;
        }
    }

    return $results;
}
函数数组\映射\关联(){
如果(func_num_args()<2)抛出new\BadFunctionCallException(“缺少参数”);
$args=func_get_args();
$callback=$args[0];
如果(!is_callable($callback))抛出new\InvalidArgumentException('First parameter must be callable');
$arrays=array\u slice($args,1);
数组(数组、函数和$a){
$a=(数组)$a;
重置(a美元);
});
$results=array();
$max_length=max(数组映射('count',$arrays));
$arrays=数组映射(函数($pole)使用($max\u长度){
返回数组_pad($pole,$max_length,null);
}美元阵列);
对于($i=0;$i<$max_length;$i++){
$elements=array();
foreach($arrays as&$v){
$elements[]=每个($v);
}
未结算(五美元);
$out=调用用户函数数组($callback,$elements);
如果($out==null)继续;
$val=isset($out[1])?$out[1]:null;
如果(isset($out[0])){
$results[$out[0]]=$val;
}否则{
$results[]=$val;
}
}
返回$results;
}
工作原理与数组映射完全相同。差不多

事实上,它并不是像你从其他语言中知道的那样纯粹的
map
。Php非常奇怪,所以它需要一些非常奇怪的用户函数,因为我们不想破坏我们精确破坏的
方法

实际上,它根本不是地图。然而,它仍然非常有用

  • 与数组映射的第一个明显区别是回调从每个输入数组中获取
    each()
    的输出,而不仅仅是值。您仍然可以一次迭代多个数组

  • 第二个区别是从回调返回键后处理键的方式;回调函数的返回值应该是
    数组('new\u key','new\u value')
    。键可以也将被更改,如果返回相同的键,相同的键甚至会导致覆盖以前的值。这不是常见的
    map
    行为,但它允许您重写键

  • 第三个奇怪的事情是,如果您在返回值中省略了
    (通过
    数组(1=>'value')
    数组(null,'value')
    ),则将分配新键,就像使用了
    $array[]=$value
    一样。这也不是
    map
    的常见行为,但我想它有时很方便

  • 第四件奇怪的事情是,如果回调函数不返回值,或者返回
    null
    ,那么整个当前键和值集将从输出中忽略,它将被跳过。这项功能完全是非
    map
    py,但如果有这样的功能,它将使该功能成为
    array\u filter\u assoc
    的绝佳特技双倍

  • 如果在回调的返回中省略了第二个元素(
    1=>…
    )(值的部分),则使用
    null
    ,而不是实际值

  • 除了回调返回中带有键
    0
    1
    的元素之外,其他元素都将被忽略

  • 最后,如果lambda返回除
    null
    或array之外的任何值,则视为忽略了键和值,因此:

  • 已为元素指定新键
  • null
    用作其值
警告:
请记住,这最后一个功能只是以前功能的一个残余,它可能是完全无用的。非常不鼓励依赖此功能,因为此功能将在将来的版本中被随机弃用和意外更改。 注:
array\u map
不同,传递到
array\u map\u assoc
的所有非数组参数(第一个回调参数除外)都以静默方式强制转换到数组

示例:
//TODO:示例,有人吗?

使用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)
    )
);

我根据以下内容创建了此函数:

例如:

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

var_dump(array_map_(function($key, $value){
    return $key . " loves " . $value;
}, $arr));
输出:

array (
  'first_key' => 'first_key loves first_value,
  'second_key' => 'second_key loves second_value',
)
当然,您可以使用
数组_值
准确返回OP想要的内容

array_values(array_map_(function($key, $value){
    return $key . " loves " . $value;
}, $test_array))

这可能是最短、最简单的理由:

$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')
)
library*非常适合执行此类任务。它是来自.NET的LINQ端口,完全支持所有回调中的值和键,类似于SQL。例如:

$mapped_array = from($test_array)
    ->select(function ($v, $k) { return "$k loves $v"; })
    ->toArray();
$test_array = array("first_key" => "first_value", 
                    "second_key" => "second_value");

var_dump(array_map2(function($a, $b) { return "$a loves $b"; }, $test_array));
或者只是:

$mapped_iterator = from($test_array)->select('"$k loves $v"');
这里,
“$k爱$v”
是该库支持的完整闭包语法的快捷方式<代码>toArray()
最后是可选的。方法链返回一个迭代器,因此如果只需要使用
foreach
对结果进行迭代,则可以删除
toArray
调用


*由我开发的

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

function array_map_assoc(callable $f, array $a) {
    return array_column(array_map($f, array_keys($a), $a), 1, 0);
}
可调用的
array(3) {
  ["new first"]=>
  string(7) "new 1st"
  ["new second"]=>
  string(7) "new 2nd"
  ["new third"]=>
  string(7) "new 3rd"
}
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));
function array_map_assoc(callable $f, array $a) {
    return array_merge(...array_map($f, array_keys($a), $a));
}
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;
    }, []);
}
$ordinals = [
    'first' => '1st',
    'second' => '2nd',
    'third' => '3rd',
];

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

var_dump(array_map_assoc($func, $ordinals));
$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)));
$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));
/**
 * @param  array    $array
 * @param  callable $callback
 * @return array
 */
function arrayMap(array $array, callable $callback)
{
    $newArray = [];

    foreach( $array as $key => $value )
    {
        $newArray[] = call_user_func($callback, $value, $key, $array);
    }

    return $newArray;
}
$testArray = [
    "first_key" => "first_value", 
    "second_key" => "second_value"
];

var_dump(
    arrayMap($testArray, function($value, $key) {
        return $key . ' loves ' . $value;
    });
);
function array_map_associative(callable $callback, $array) {
    /* map original array keys, and call $callable with $key and value of $key from original array. */
    return array_map(function($key) use ($callback, $array){
        return $callback($key, $array[$key]);
    }, array_keys($array));
}
array(2) {
  [0]=>
  string(27) "first_key loves first_value"
  [1]=>
  string(29) "second_key loves second_value"
}
function array_map2(callable $f, array $a)
{
    return array_map($f, array_keys($a), $a);
}
$test_array = array("first_key" => "first_value", 
                    "second_key" => "second_value");

var_dump(array_map2(function($a, $b) { return "$a loves $b"; }, $test_array));
$myArray = [
    "key0" => 0,
    "key1" => 1,
    "key2" => 2
];

array_combine(
    array_keys($myArray),
    array_map(
        function ($intVal) {
            return strval($intVal);
        },
        $myArray
    )
);
array(3) {
  ["key0"]=>
  string(1) "0"
  ["key1"]=>
  string(1) "1"
  ["key2"]=>
  string(1) "2"
}
$test_array = [
    "first_key"     => "first_value",
    "second_key"    => "second_value"
];

$f = function($ar) {
    return array_map(
        function($key, $val) {
            return "{$key} - {$val}";
        },
        array_keys($ar),
        $ar
    );
};

#-- WITHOUT preserving keys
$res = $f($test_array);

#-- WITH preserving keys
$res = array_combine(
    array_keys($test_array),
    $f($test_array)
);
$array = [
  'category1' => 'first category',
  'category2' => 'second category',
];
 
$new = array_map(function($key, $value) {
  return "{$key} => {$value}";
}, array_keys($array), $array);
$test_array = [
    "first_key" => "first_value", 
    "second_key" => "second_value",
];

$x_result = (function(array $arr) {
    foreach ($arr as $key => $value) {
        yield "$key loves $value";
    }
})($test_array);

var_dump(iterator_to_array($x_result));

// array(2) {
//   [0]=>
//   string(27) "first_key loves first_value"
//   [1]=>
//   string(29) "second_key loves second_value"
// }
function xmap(callable $cb, array $arr)
{
    foreach ($arr as $key => $value) {
        yield $cb($key, $value);
    }
}

var_dump(iterator_to_array(
    xmap(function($a, $b) { return "$a loves $b"; }, $test_array)
));