$arr = array( array( "one" => 1, "two-two" => 2, "four" => 4),
array( "two-two" => 22, "three" => 33, "four" => 44));
$keys = array_flip( array_keys( call_user_func_array( 'array_merge', $arr ) ) );
array_walk( $keys, function( &$val, $key ){ $val = ucwords( str_replace( array( "_", "-" ), " ", $key ) ); } );
print_r( $keys );
结果:
Array ( [one] => One [two-two] => Two Two [four] => Four [three] => Three )
代码:
我觉得这里应该有一个单行,不能看到它。你能吗?
答案 0 :(得分:1)
好吧,你可以使用array_walk_recursive。虽然它不是单行,但你用这个函数调用较少的函数。
$arr = array( array( "one" => 1, "two-two" => 2, "four" => 4),
array( "two-two" => 22, "three" => 33, "four" => 44));
$res = array();
array_walk_recursive($arr, function ($val, $key) use (&$res) {
$res[$key] = ucwords(str_replace(array('_', '-'), ' ', $key));
});
答案 1 :(得分:1)
我将通过几次代码迭代,并解释我一直在采取的步骤。我的大多数决定都源于始终降低复杂性的需要。例如,当您使用array_walk
时,您是否必须考虑如何通过数组进行迭代?您是否考虑过数组索引或确保在每次迭代后增加?不,array_walk
是强大的,因为它隐藏那些令人讨厌的细节远离程序员 - 但是这些事情不会让我们担心。
那你为什么要担心这样的烦恼?
ucwords( str_replace( array( "_", "-" ), " ", $key ) )
这是它自己的功能,我们称之为humanIdentifier
。它需要一些程序化的$key
值并返回一个漂亮的,人性化的字符串
function humanIdentifier ($x) {
return ucwords(str_replace('-', ' ', $x));
}
通过这一个小小的改变,我们将已经简化了你的代码的很多的 - 复杂性下降,因为我们不再需要担心的如何的做钥匙到人类可读的字符串转换。那些令人讨厌的细节已被抽象掉了。
// things are improving ...
array_walk( $keys, function( &$val, $key ){ $val = humanIdentifier($val); } );
这是我将采取的方法,因为我继续研究这个答案的其他部分
array_map
糟透了
许多功能性居民(例如)array_reduce
,array_map
,array_filter
,array_walk
都是PHP中的灾难。接口是非常不一致的,行为有时只是简直不可思议。正如您和其他人所指出的那样,array_map
并没有为我们提供访问键的方法,但是没有什么可以阻止您制作一个可以访问它的通用函数。< / p>
function array_kmap (callable $f, iterable $xs) {
return array_reduce(array_keys($xs), function ($acc, $k) use ($xs, $f) {
return array_merge($acc, [$k => call_user_func($f, $k, $xs[$k], $xs)]);
}, []);
}
结合您的humanIdentifier功能,我们可以很容易地找到解决方案
$a = [
['one' => 1, 'two-two' => 2, 'four' => 4],
['two-two' => 22, 'three' => 33, 'four' => 44]
];
$b = array_reduce($a, function ($acc, $x) {
return array_merge($acc, array_kmap(function ($k, $v) {
// we don't actually use `$v`, so we can ignore it
return humanIdentifier($k);
}, $x));
}, []);
print_r($b);
// Array
// (
// [one] => One
// [two-two] => Two Two
// [four] => Four
// [three] => Three
// )
隐藏的复杂性
在$a
到$b
的转换中仍然隐藏着一些复杂性。你能发现它吗? array_reduce
几乎是用于迭代的大多数功能的祖父 - 它非常强大,但它必须将这种功能归功于其极其通用的界面。我们对array_reduce
的使用几乎是array_merge
和我们的映射函数$f
的包装。我们可以推导出一个新功能,它可以作为一种专门的array_reduce
- 大多数函数式语言称之为平面地图。
function array_flatmap (callable $f, iterable $xs) {
return array_reduce(array_map($f, $xs), 'array_merge', []);
}
$a = [
['one' => 1, 'two-two' => 2, 'four' => 4],
['two-two' => 22, 'three' => 33, 'four' => 44]
];
$b = array_flatmap(function ($x) {
return array_kmap(function ($k) {
return humanIdentifier($k);
}, $x);
}, $a);
print_r($b);
// Array
// (
// [one] => One
// [two-two] => Two Two
// [four] => Four
// [three] => Three
// )
转换
什么? Eta conversion来自lambda演算,并说
function ($x) { return $f($x); } === $f
(function ($x) { return $f($x); })($y) === $f($y)
$f($y) === $f($y)
$f === $f
我提到这一点是因为我们可以通过eta转换一些代码来降低更多的复杂性。有两个eta转换可以帮助我们的程序。你看到了哪里?
array_kmap(function ($k) {
return humanIdentifier($k);
}, $x)
这个悬空$k
可以轻松删除 - 这里是简化但等效的代码(注意:这是可能的,因为我们从您的可调用中丢弃$v
值 - 只需要密钥计算我们的转型)
array_kmap('humanIdentifier', $x)
现在,如果我们稍微缩小一下,我们会看到这个!
function ($x) {
return array_kmap('humanIdentifier', $x);
}
我们的$x
函数末尾的另一个小悬空array_kmap
!如果我们partially apply我们的array_kmap
功能,我们可以删除$x
point这将摆脱function ($x) { ... }
完全。
当然PHP没有任何部分应用函数的方法,所以我们必须做到这一点
function partial (callable $f, ...$xs) {
return function (...$ys) use ($f, $xs) {
return call_user_func($f, ...$xs, ...$ys);
};
}
现在我们的结果转变是一件美丽的事情
$a = [
['one' => 1, 'two-two' => 2, 'four' => 4],
['two-two' => 22, 'three' => 33, 'four' => 44]
];
$b = array_flatmap(partial('array_kmap', 'humanIdentifier'), $a);
print_r($b);
// Array
// (
// [one] => One
// [two-two] => Two Two
// [four] => Four
// [three] => Three
// )
代码反映数据反映代码
...数据反映代码反映数据......看看我们最后的代码:
$b = array_flatmap(partial('array_kmap', 'humanIdentifier'), $a);
我们正在做一个array_map的array_map - 这是有道理的,因为我们的初始数据是一个数组数组!在这里,我们的代码设计反映了它所运行的数据的形状。
这很好,因为即使我们没有写这个,我们也可以查看这段代码,并立即知道它的工作意义的数据形态
将所有内容放在一起
为了节省您收集上述所有代码段的时间,这里是一个带有验证输出的完整可运行脚本
function array_kmap (callable $f, iterable $xs) {
return array_reduce(array_keys($xs), function ($acc, $k) use ($xs, $f) {
return array_merge($acc, [$k => call_user_func($f, $k, $xs[$k], $xs)]);
}, []);
}
function humanIdentifier ($x) {
return ucwords(str_replace('-', ' ', $x));
}
function array_flatmap (callable $f, iterable $xs) {
return array_reduce(array_map($f, $xs), 'array_merge', []);
}
function partial (callable $f, ...$xs) {
return function (...$ys) use ($f, $xs) {
return call_user_func($f, ...$xs, ...$ys);
};
}
$a = [
['one' => 1, 'two-two' => 2, 'four' => 4],
['two-two' => 22, 'three' => 33, 'four' => 44]
];
$b = array_flatmap(partial('array_kmap', 'humanIdentifier'), $a);
print_r($b);
// Array
// (
// [one] => One
// [two-two] => Two Two
// [four] => Four
// [three] => Three
// )
<强>备注强>
与您在问题中发布的原始代码相比,我们在此处编写了大量代码。所以也许你想知道这是一个怎样的改进。嗯,这是一个定性测量,并且在很多方面(例如速度,效率),这个答案可能更糟。但在其他领域(例如可读性,可维护性),我看到了一个显着的进步。
和其他人一样,当我第一次阅读你的代码时,我正在摸不着它的所作所为。看看由此产生的转变,我可以更容易地推断出发生了什么,因为我不太关注 事情如何被转变,我可以专注于重要的部分。
如果你眯着眼睛,这基本上就是我们必须关注的一切
// input is array of arrays
$a = array(array( ... ))
// output requires map of map of input
$b = map(map( ... humanIdentifier ))
我们也做了很多其他事情,比如避免不必要的任务,重新分配或突变。创建$a
后,$b
不受影响。随着我们的计划不断发展,避免这样的副作用有助于提高可读性并降低复杂性。无论如何,这些都超出了这个答案的范围,但我想我会提到它们。
希望有所帮助^ _ ^
答案 2 :(得分:0)
不是一行,但您仍然可以删除换行符。
$output = [];
foreach ($arr as $subarray) { foreach ($subarray as $key => $value) {
$output[$key] = ucwords(str_replace(array("_", "-"), " ", $key));
} }
答案 3 :(得分:0)
$arr = array(
array("one" => 1, "two-two" => 2, "four" => 4),
array("two-two" => 22, "three" => 33, "four" => 44)
);
以明确的功能方式:
$keys = array_keys(call_user_func_array('array_merge', $arr));
$formattedKeys = array_map(
function($key) {return ucwords(str_replace(array('_', '-'), ' ', $key));},
$keys
);
print_r(array_combine($keys, $formattedKeys));
或者只是简短地说:
$keys = array();
foreach(array_keys(call_user_func_array('array_merge', $arr)) as $key)
$keys[$key] = ucwords(str_replace(array('_', '-'), ' ', $key));
print_r($keys);
或者:
$keys = array();
foreach(call_user_func_array('array_merge', $arr) as $key=>$unused)
$keys[$key] = ucwords(str_replace(array('_', '-'), ' ', $key));
print_r($keys);
如果$arr
始终包含两个项,您还可以将call_user_func_array('array_merge', $arr)
替换为$arr[0]+$arr[1]
(array_merge($a, $b)
和$a+$b
不同只在值中,而不是在键中。)