Php 基于部分数组键组合数组项
我有一个给定的多维数组,如:Php 基于部分数组键组合数组项,php,arrays,Php,Arrays,我有一个给定的多维数组,如: $givenArray = [ 'one__111__' => [ 'more' => '000'], 'one__111__xyz' => [ 'more' => '000'], 'hey__121__' => [ 'more' => '000'], 'hey__121__abc' => [ 'more' => '000'], 'zzz__212__' => [ 'mor
$givenArray = [
'one__111__' => [ 'more' => '000'],
'one__111__xyz' => [ 'more' => '000'],
'hey__121__' => [ 'more' => '000'],
'hey__121__abc' => [ 'more' => '000'],
'zzz__212__' => [ 'more' => '000'],
'zzz__212__b' => [ 'more' => '000'],
'abc__3__' => [ 'more' => '000'],
];
如果它们以相同的密钥名开始,我需要映射这些对。因此,one_uu111_u
和one_u111_uxyz
是一对
结果应该如下所示:
[
['one__111__'] => [
[0] => ['one__111__' => ['more' => '000']],
[1] => ['one__111__xyz' => ['more' => '000']]
],
['hey__121__'] =>
[0] => ['hey__121__' => ['more' => '000']],
[1] => ['hey__121__abc' => ['more' => '000']]
]
['zzz__212__'] =>
[0] => ['zzz__212__' => ['more' => '000']],
[1] => ['zzz__212__b' => ['more' => '000']]
]
['abc__3__'] =>
[0] => ['abc__3__' => ['more' => '000']]
]
]
这就是我尝试过的。我相信是O(n2)
我搜索了数组filter/reduce/map函数,但找不到“正确”的函数。应该使用哪个数组函数?就像我想我需要一个数组函数,它迭代每个项目,并允许我传入新创建的数组。PHP中有这样的函数吗
这应该可以-
$new = [];
$keys = [];
// Extract keys as per pattern
foreach ($givenArray as $key => $val) {
preg_match('/[a-z]+\_+\d+\_+/', $key, $match);
$keys[] = $match[0];
}
// filter array for each extracted keys
foreach ($keys as $key) {
$new[$key] = array_filter($givenArray, function($k) use($key) {
return strpos($k, $key) !== false;
}, ARRAY_FILTER_USE_KEY);
}
输出
Array
(
[one__111__] => Array
(
[one__111__] => Array
(
[more] => 000
)
[one__111__xyz] => Array
(
[more] => 000
)
)
[hey__121__] => Array
(
[hey__121__] => Array
(
[more] => 000
)
[hey__121__abc] => Array
(
[more] => 000
)
)
[zzz__212__] => Array
(
[zzz__212__] => Array
(
[more] => 000
)
[zzz__212__b] => Array
(
[more] => 000
)
)
[abc__3__] => Array
(
[abc__3__] => Array
(
[more] => 000
)
)
)
这应该是有效的-
$new = [];
$keys = [];
// Extract keys as per pattern
foreach ($givenArray as $key => $val) {
preg_match('/[a-z]+\_+\d+\_+/', $key, $match);
$keys[] = $match[0];
}
// filter array for each extracted keys
foreach ($keys as $key) {
$new[$key] = array_filter($givenArray, function($k) use($key) {
return strpos($k, $key) !== false;
}, ARRAY_FILTER_USE_KEY);
}
输出
Array
(
[one__111__] => Array
(
[one__111__] => Array
(
[more] => 000
)
[one__111__xyz] => Array
(
[more] => 000
)
)
[hey__121__] => Array
(
[hey__121__] => Array
(
[more] => 000
)
[hey__121__abc] => Array
(
[more] => 000
)
)
[zzz__212__] => Array
(
[zzz__212__] => Array
(
[more] => 000
)
[zzz__212__b] => Array
(
[more] => 000
)
)
[abc__3__] => Array
(
[abc__3__] => Array
(
[more] => 000
)
)
)
只要键按示例数据中所示进行排序,您只需将当前键与插入到输出数组中的最后一个键进行比较:
$result = [];
$resultItemKey = '#'; // something that a key can't start with
foreach($givenArray as $key => $value) {
if(substr($key, 0, strlen($resultItemKey)) === $resultItemKey) {
$result[$resultItemKey][] = [$key => $value];
}
else {
$result[$key][] = [$key => $value];
$resultItemKey = $key;
}
}
输出太长,无法在此显示,但符合要求
请注意,如果未对键进行排序,则始终可以使用按键对数组进行排序。只要按示例数据中所示对键进行排序,您只需将当前键与插入到输出数组中的最后一个键进行比较:
$result = [];
$resultItemKey = '#'; // something that a key can't start with
foreach($givenArray as $key => $value) {
if(substr($key, 0, strlen($resultItemKey)) === $resultItemKey) {
$result[$resultItemKey][] = [$key => $value];
}
else {
$result[$key][] = [$key => $value];
$resultItemKey = $key;
}
}
输出太长,无法在此显示,但符合要求
请注意,如果未对键进行排序,则始终可以使用按键对数组进行排序。您可以先按键排序,然后“查看”下一个键,直到您停止查找与当前键以相同字符串开头的键为止 这会把你降到O(n)㏒ n) :
ksort($givenArray);//如果要保留原始阵列,请先克隆它
$result=[];
对于($i=0;$i[$givenArray[$thisKey]]];
而($i
您可以先按键排序,然后“窥视”下一个键,直到您停止查找与当前键以相同字符串开头的键为止,从而提高性能
这会把你降到O(n)㏒ n) :
ksort($givenArray);//如果要保留原始阵列,请先克隆它
$result=[];
对于($i=0;$i[$givenArray[$thisKey]]];
而($i
由于要查找前缀匹配和添加操作,因此可以构建数据结构。每个节点将携带它自己的子节点,以及当许多键具有相同前缀时,它最终将保存的数据
<?php
class Node{
public $char,$data,$children,$end,$key;
function __construct($char){
$this->char = $char;
$this->data = [];
$this->children = [];
$this->end = false;
}
}
class Trie{
private $root,$result;
function __construct($data){
$this->root = new Node('~');
$this->result = [];
foreach($data as $key => $value){
$this->insert($key);
}
foreach($data as $key => $value){
$this->add($key,$value);
}
}
private function insert($key){
$temp = $this->root;
$len = strlen($key);
for($i=0;$i<$len;++$i){
if(!isset($temp->children[$key[$i]])){
$temp->children[$key[$i]] = new Node($key[$i]);
}
$temp = $temp->children[$key[$i]];
if($temp->end) break;
}
if(!$temp->end) $temp->key = $key;
$temp->end = true;
}
private function add($key,$value){
$temp = $this->root;
$len = strlen($key);
for($i=0;$i<$len;++$i){
$temp = $temp->children[$key[$i]];
if($temp->end) break;
}
$temp->data[] = [$key => [$value]];
}
public function getResult(){
$this->getResultHelper($this->root);
return $this->result;
}
private function getResultHelper(Node $root){
if($root->end){
$this->result[$root->key] = $root->data;
return;
}
foreach($root->children as $key => $node){
$this->getResultHelper($node);
}
}
}
print_r((new Trie($givenArray))->getResult());
由于您正在查找前缀匹配和添加操作,因此可以构建数据结构。每个节点将携带它自己的子节点,以及当许多键具有相同前缀时,它最终将保存的数据
<?php
class Node{
public $char,$data,$children,$end,$key;
function __construct($char){
$this->char = $char;
$this->data = [];
$this->children = [];
$this->end = false;
}
}
class Trie{
private $root,$result;
function __construct($data){
$this->root = new Node('~');
$this->result = [];
foreach($data as $key => $value){
$this->insert($key);
}
foreach($data as $key => $value){
$this->add($key,$value);
}
}
private function insert($key){
$temp = $this->root;
$len = strlen($key);
for($i=0;$i<$len;++$i){
if(!isset($temp->children[$key[$i]])){
$temp->children[$key[$i]] = new Node($key[$i]);
}
$temp = $temp->children[$key[$i]];
if($temp->end) break;
}
if(!$temp->end) $temp->key = $key;
$temp->end = true;
}
private function add($key,$value){
$temp = $this->root;
$len = strlen($key);
for($i=0;$i<$len;++$i){
$temp = $temp->children[$key[$i]];
if($temp->end) break;
}
$temp->data[] = [$key => [$value]];
}
public function getResult(){
$this->getResultHelper($this->root);
return $this->result;
}
private function getResultHelper(Node $root){
if($root->end){
$this->result[$root->key] = $root->data;
return;
}
foreach($root->children as $key => $node){
$this->getResultHelper($node);
}
}
}
print_r((new Trie($givenArray))->getResult());
我认为密钥名称没有固定的长度/结构?@Nick没错,密钥是否总是按照示例数据中所示进行排序?@Nick luckley是的,但未来可能会发生变化future@caramba如果子前缀有自己的子前缀怎么办?我认为密钥名称没有固定的长度/结构?@Nick是的,密钥总是按照示例数据中所示进行排序吗?@Nick Luckley是的,但未来可能会发生变化future@caramba如果子前缀有自己的子前缀呢?我喜欢先生成keys数组的想法。正如我的问题所写的,钥匙确实有一个模式。在现实生活中,虽然这些键没有遵循这样的模式,但这仍然是O(n2),就像您的原始代码一样。如果模式不同并且有大量数据,那么应该避免这种情况,就像首先生成键数组的想法一样。正如我的问题所写的,钥匙确实有一个模式。在现实生活中,虽然这些键没有遵循这样的模式..但这仍然是O(n2),就像您的原始代码一样。如果模式不同并且有大量数据,那么应该避免这样:facepalm,这么简单$resultItemKey
甚至可以设置为空字符串$resultItemKey=''
..@caramba不,不能将其设置为空字符串,因为substr($key,0,strlen($resultItemKey))
将返回'
,而不管$key
的值是多少,该值都将匹配'
,但只有在密钥为空时才会发生这种情况,对吗?我总是希望有一把钥匙。。我猜#
作为初始值可能更可靠。如果一个键是空的,那么之后的所有内容都会匹配它,因为空字符串是其他字符串的子字符串。对于您的数据来说,这似乎不是一个有效的场景。另一方面,它可能是null
,并且可以添加额外的null检查来检查它是否是第一次。可能比试图找到一个不是任何键前缀的字符串更容易:facepalm,这么容易$resultItemKey
甚至可以设置为空字符串$resultItemKey=''
..@caramba不,不能将其设置为空字符串,因为substr($key,0,strlen($resultItemKey))
将返回'
,而不管$key
的值是多少,该值都将匹配'
,但只有在密钥为空时才会发生这种情况,对吗?我总是希望有一把钥匙。。我猜#
作为初始值可能更可靠。如果一个键是空的,那么之后的所有内容都会匹配它,因为空字符串是其他字符串的子字符串。对于您的数据来说,这似乎不是一个有效的方案。另一方面,它可能是null
,并且可以添加额外的null检查