Cakephp 使用extract检索多个数组值
编辑: 因此,我想检索以下内容:Cakephp 使用extract检索多个数组值,cakephp,Cakephp,编辑: 因此,我想检索以下内容: array( [0]=> [index1]=>something [index2]=>something else [index3]=>something more [1]=> [index1]=>something [index2]=>something else [index3]=>something
array(
[0]=>
[index1]=>something
[index2]=>something else
[index3]=>something more
[1]=>
[index1]=>something
[index2]=>something else
[index3]=>something more
[2]=>
[index1]=>something
[index2]=>something else
[index3]=>something more
)
如何使用cakephp中的Set::extract函数获取数组的多个索引
这将检索一个值:
array(
[0]=>
[index1]=>something
[index2]=>something else
[1]=>
[index1]=>something
[index2]=>something else
[2]=>
[index1]=>something
[index2]=>something else
)
但我想得到多个值。。。比如,index1和index2
我试过下面这样的说法,但没有用
Set::extract($array, '{n}.index1');
编辑
Set::extract($array, '[{n}.index1, {n}.index2']);
输出:
$__pages = Hash::merge(
Hash::extract($pages, 'pages.{n}.id'),
Hash::extract($pages, 'pages.{n}.title')
);
pr($__pages);
这对我没有帮助,因为我仍然需要这样的联系:
Array
(
[0] => 2
[1] => 4
[2] => 104
[3] => Sample Page
[4] => about us
[5] => Services
)
我甚至会很高兴:
Array(
[2] => Sample Page
[4] => About us
[104] => Services
)
回答
代码悖论的答案适用于我提供的测试代码。这是现实生活中的代码,以防有人在这里绊倒。
在这本书中,它指出,“除了{n}和{s}之外,任何括在括号中的字符串文字都被解释为正则表达式。”
这条线似乎是隐藏的,不是很明显。所以知道了这一点,我只是使用正则表达式规则来检索我需要的数据。我有一个从api中提取wordpress帖子的数组,我需要将结果缩小到id,title
Array(
Array(id => 2, title => Sample Page)
Array(id => 4, title => About Us)
Array(id => 104, title => Services)
)
为了仅检索id和标题,我添加了以下行
array(
posts=>
0=>
id => 3
slug => sample-page
type => page
title => Sample Page
//...and so on
1=>
id => 7
slug => sample-page-2
type => page
title => Sample Page 2
//...and so on
这给了我:
pr(Set::classicExtract($pages, 'pages.{n}.{(id|title)}'));
文档:您是否尝试过Set::extract($array,{n}.{s}') 编辑:如果您的数组维度与答案中的维度完全相同,您可以尝试使用数组_键(Set::extract($array,{n}.{s}') 一种方法(如果您只想保留一些结果): 另一种方法(如果您只想删除一些):
我不知道你为什么要坚持使用
Set
类?如果它不适合您的需要,为什么您要完全使用它而不创建自己的功能?
您在一条注释中表示希望避免foreach
循环。但是Set
类方法本身充满了foreach
循环。我可能没抓住要点
个人而言,我只需使用如下函数即可:
Hash::remove($array, '{n}.index3');
下面是一个它将返回的示例:
function filter_fields($array_to_filter, $fields_to_keep)
{
foreach($array_to_filter as $i => $sub_array)
{
foreach($sub_array as $field => $value)
{
if(!in_array($field, $fields_to_keep))
{
unset($array_to_filter[$i][$field]);
}
}
}
return $array_to_filter;
}
布景太棒了!不能使用Set::extract直接执行此操作,但可以使用Set::combine构建两个数组索引的关联数组:
print_r($array_to_filter);
/*
Array
(
[0] => Array
(
[index1] => abc
[index2] => def
[index3] => ghi
)
[1] => Array
(
[index1] => jkl
[index2] => mno
[index3] => poq
)
)
*/
$filtered_array = filter_fields($array_to_filter, array('index1', 'index3'));
print_r($filtered_array);
/*
Array
(
[0] => Array
(
[index1] => abc
[index3] => ghi
)
[1] => Array
(
[index1] => jkl
[index3] => poq
)
)
*/
工作示例如下所示:
Set::combine($myArray, '{n}.index1', '{n}.index2')
这将采用您提到的阵列:
$myArray = array(
array('index1'=>'something 1', 'index2'=>'something else 1', 'index3'=>'something more 1'),
array('index1'=>'something 2', 'index2'=>'something else 2', 'index3'=>'something more 2'),
array('index1'=>'something 3', 'index2'=>'something else 3', 'index3'=>'something more 3'),
);
debug(Set::combine($myArray, '{n}.index1', '{n}.index2'));
)
把它变成这样:
array(
[0]=>
[index1]=>something 1
[index2]=>something else 1
[index3]=>something more 1
[1]=>
[index1]=>something 2
[index2]=>something else 2
[index3]=>something more 2
[2]=>
[index1]=>something 3
[index2]=>something else 3
[index3]=>something more 3
[+10]在这篇文章中向我展示了classicExtract方法,大家都竖起大拇指 示例阵列:
$arr = array(
array(
'index1'=>'something',
'index2'=>'something else',
'index3'=>'something more',
),
array(
'index1'=>'something',
'index2'=>'something else',
'index3'=>'something more',
),
array(
'index1'=>'something',
'index2'=>'something else',
'index3'=>'something more',
)
);
$output = Set::classicExtract($arr, '{n}.{index[1-2]}');
print_r($output);
// output
Array
(
[0] => Array
(
[index1] => something
[index2] => something else
)
[1] => Array
(
[index1] => something
[index2] => something else
)
[2] => Array
(
[index1] => something
[index2] => something else
)
)
我遇到的问题是:
基键被转换为int
$params = array(
'key-1'=>array('subkey'=>array('x'), 'junk'),
'key-2'=>array('subkey'=>array('y'), 'otherkey'=>'more junk')
);
解决方案:
eg. array(0=>array('x'), 1=>array('y'))
返回:
$array = Hash::filter(Set::classicExtract($params, '{[a-zA-Z0-9-_.]}.subkey'));
根据需要修改注册表项中的正则表达式
刚刚写了这个函数
它将提供使用{a)而不是{s}解析数组的能力
{a} 用于基础的关联键
这样调用:static::extract($array,{a}.subkey')
[[蛋糕3更新]]
如果您正在使用此函数,我看到cakephp刚刚删除了set类。您可以通过向类中添加classicExtract方法使其重新工作
public static function extract($array, $path, $filter=true){
$path = str_replace("{a}", "{[a-zA-Z0-9-_.]}", $path);
if(is_array($array)){
$return = Set::classicExtract($array, $path);
if($filter){
if(is_array($return)){
$return = Hash::filter($return);
}
}
return $return;
}
}
这将返回数组中的所有字符串。我知道你在说什么。我应该重写这个问题,我需要随键一起提供值。我想我在这里遗漏了一些东西……假设你有这个数组:$array=array(array('index1'=>'something','index2'=>'something','index3'=>'something more'),array('index1'=>'something'、'index2'=>'something other'、'index3'=>'something more'));然后从子数组中访问键和值就像获取$array[index]一样简单,否?我简化了数组。该数组可能有数百个具有相同键的嵌套数组。试图避免foreach循环。我理解,但问题是:第二级数组中的键可以重复?就像我上面的示例中,第二个子数组中也有index1、index2和Index3?在这种情况下,具体做什么你想得到结果吗?你应该先放置一个包含2或3个子数组的初始数组,然后放置一个示例数组来指定你想要得到的数组的格式,就像你在这里的第一个方法一样,我认为这很接近。我更新了我的问题,以便向你提供我这样做时得到的输出。格式有点不合适,因为我仍然需要id和标题才能成为关联。谢谢你的回答。当我说我想避免foreach循环时,是因为我已经知道如何这样做。我正在寻找一个更“蛋糕”方法。我觉得新的cakephp 2.x文档在很多方面都有不足之处,希望有人能找到答案。自从我迁移到2.x后,由于缺少文档,我用谷歌搜索了我的大部分问题。api很棒,但烹饪书却不是。我相信你自己知道怎么做:-)但是如果Cake库不能,这也是创建您自己的函数的另一个原因。这可以在一行中完成,$filtered=Hash::remove($array,{n}.index3');如果我们只想丢弃一个字段,这是正确的。但是对于更多的字段,Hash::remove()将不得不被多次呼叫,这将降低性能。@Tim Joyce请测试我的答案。我希望你能得到你想要的答案。谢谢。谢谢你。你回答了我的问题,并引导我走上了正确的道路来研究为什么这样做有效,并且我能够将其适应我的现实生活代码。我正在用我的发现更新我的问题。看起来和set类一样,set类也被贬低了,取而代之的是Hash-classquestion,它为后面的人更新。
eg. array(0=>array('x'), 1=>array('y'))
$array = Hash::filter(Set::classicExtract($params, '{[a-zA-Z0-9-_.]}.subkey'));
eg. array('key-1'=>array('x'), 'key-2'=>array('y'))
public static function extract($array, $path, $filter=true){
$path = str_replace("{a}", "{[a-zA-Z0-9-_.]}", $path);
if(is_array($array)){
$return = Set::classicExtract($array, $path);
if($filter){
if(is_array($return)){
$return = Hash::filter($return);
}
}
return $return;
}
}
use Cake\Utility\Hash;
public static function classicExtract($data, $path = null)
{
if (empty($path)) {
return $data;
}
if (is_object($data)) {
if (!($data instanceof \ArrayAccess || $data instanceof \Traversable)) {
$data = get_object_vars($data);
}
}
if (empty($data)) {
return null;
}
if (is_string($path) && strpos($path, '{') !== false) {
$path = \Cake\Utility\String::tokenize($path, '.', '{', '}');
} elseif (is_string($path)) {
$path = explode('.', $path);
}
$tmp = array();
if (empty($path)) {
return null;
}
foreach($path as $i => $key) {
if (is_numeric($key) && intval($key) > 0 || $key === '0') {
if (isset($data[$key])) {
$data = $data[$key];
} else {
return null;
}
} elseif ($key === '{n}') {
foreach($data as $j => $val) {
if (is_int($j)) {
$tmpPath = array_slice($path, $i + 1);
if (empty($tmpPath)) {
$tmp[] = $val;
} else {
$tmp[] = static::classicExtract($val, $tmpPath);
}
}
}
return $tmp;
} elseif ($key === '{s}') {
foreach($data as $j => $val) {
if (is_string($j)) {
$tmpPath = array_slice($path, $i + 1);
if (empty($tmpPath)) {
$tmp[] = $val;
} else {
$tmp[] = static::classicExtract($val, $tmpPath);
}
}
}
return $tmp;
} elseif (strpos($key, '{') !== false && strpos($key, '}') !== false) {
$pattern = substr($key, 1, -1);
foreach($data as $j => $val) {
if (preg_match('/^'.$pattern.'/s', $j) !== 0) {
$tmpPath = array_slice($path, $i + 1);
if (empty($tmpPath)) {
$tmp[$j] = $val;
} else {
$tmp[$j] = static::classicExtract($val, $tmpPath);
}
}
}
return $tmp;
} else {
if (isset($data[$key])) {
$data = $data[$key];
} else {
return null;
}
}
}
return $data;
}
//CAKEPHP METHODS
public static function extract($array, $path, $filter = true)
{
$return = [];
if (is_array($array)) {
if (stristr($path, '{a}')) {
$return = static::classicExtract($array, str_replace("{a}", "{[a-zA-Z0-9-_. ]}", $path));
} else {
$return = Hash::extract($array, $path);
}
}
if ($filter && is_array($return)) {
$return = Hash::filter($return);
}
return $return;
}