我在PHP中有一个多维数组,其中外部数组包含数千个项目,其中每个项目都是一个数组本身,其值为" key1"," key2"和"计算":
myExistingArray (size=99999 VERY BIG)
public 0 =>
array (size=3)
'key1' => string '15504'
'key2' => string '20'
'count' => string '1'
public 1 =>
array (size=3)
'key1' => string '15508' (length=5)
'key2' => string '20' (length=2)
'count' => string '2' (length=1)
public 2 =>
array (size=3)
'key1' => string '15510' (length=5)
'key2' => string '20' (length=2)
'count' => string '5' (length=1)
....many more similar items
我想把它转换成一个非常简单的数组,其中前者来自" key1"和"关键"被连接成一个新的键,指向相应的"计数"像这样的价值:
myNewArray (size=99999 VERY BIG)
<key1>_<key2> => <count>
15504_20 => string '1' (length=1)
15508_20 => string '2' (length=1)
15510_20 => string '5' (length=1)
性能对我来说非常重要,因为外部数组有几千个项目。 PHP中有快速方法吗?我唯一得到的是一个简单的迭代,但这对我来说似乎很慢:
// works but I am looking for a faster version
$myNewArray = array();
foreach ($myExistingArray as $item) {
$myNewArray [$item["key1"]."_".$item["key1"]]=$item["count"];
}
编辑/潜在问题
有些人正确地补充说我当前的解决方案已经在O(n)中并且提到PHP中没有内置函数来加速这一点。
我得到了#34; myExistingArray&#34;来自mysql数据库查询。我基本上有工作对象,并希望按状态和event_id对它们进行分组。查询与此类似:
select count(job.id) as count, job.status as key1, job.event_id as key2
from job
group by job.status, job.event_id
我想重新排列密钥,以便稍后我可以轻松访问具有特定状态的特定事件的作业计数。
答案 0 :(得分:2)
通常,你正在寻找array_walk
或array_map
函数来转换PHP中的数组,但不幸的是它们都不能改变你想要转换的数组的键。 array_walk
将保留密钥,但不会更改密钥。可悲的是,不,没有内置的功能来做你所要求的。
答案 1 :(得分:1)
使用以下结果完成一些测试(几乎全部相同)。
Test 1: [0.25861501693726]
Test 2: [0.20804476737976]
Test 3: [0.21039199829102]
Oldskool:[0.26545000076294]
Test 4: [0.35072898864746]
在合并的数组上执行var_dump()
会降低速度(如预期的那样),但是如果保留内存,数据就不会太糟糕了。
PHP用于测试:
// Construct the raw data
$i = 0;
do {
$raw[] = array('key1' => mt_rand(10000,99999), 'key2' => mt_rand(10,99), 'count' => $i);
} while(++$i < 100000);
// Test 1
$before = microtime(true);
foreach($raw as $k => $v) {
$clean[$v['key1'].'_'.$v['key2']] = $v['count'];
}
$after = microtime(true);
echo 'Test 1:['.($after - $before).']<br />';
$clean = false;
$i = 0;
// Test 2
$before = microtime(true);
$max = count($raw);
do {
$clean[$raw[$i]['key1'].'_'.$raw[$i]['key2']] = $raw[$i]['count'];
} while(++$i < $max);
$after = microtime(true);
echo 'Test 2:['.($after - $before).']<br />';
$clean = false;
$i = 0;
// Test 3
$before = microtime(true);
$max = count($raw);
for($i; $i < $max; $i++) {
$clean[$raw[$i]['key1'].'_'.$raw[$i]['key2']] = $raw[$i]['count'];
}
$after = microtime(true);
echo 'Test 3:['.($after - $before).']<br />';
$clean = false;
// Test of Oldskool's suggestion
$before = microtime(true);
foreach (array_keys($raw) as $item) {
$clean[$raw[$item]['key1'].'_'.$raw[$item]['key2']] = $raw[$item]['count'];
}
$after = microtime(true);
echo 'Test Oldskool:['.($after - $before).']<br />';
$clean = false;
$i = 0;
// Test 4, just for fun
$before = microtime(true);
$max = count($raw);
do {
$c = array_pop($raw[$i]);
$clean[join('_', $raw[$i])] = $c;
} while(++$i < $max);
$after = microtime(true);
echo 'Test 4:['.($after - $before).']<br />';
修改:为Oldskool示例添加了测试。
答案 2 :(得分:0)
您可以将foreach更改为仅迭代键而不是整个子数组,方法是将其更改为:
Pics.find({}, {sort: {rating: -1}});
这将获得一些轻微的速度优势(请参阅时间here(array_keys方法)和here(您的原始方法)的比较)。在非常大的阵列上,差异可能会变得更加明显。
答案 3 :(得分:0)
如果速度是问题,并且您没有将最终数组用作地图,我会创建一个生成器,这样您就不必预先计算所有内容。
$myExistingArray = [ ... ];
class MyNewArrayIterator implements IteratorAggregate {
protected $array;
public function __construct(array $array) {
$this->array = $array;
}
public function getIterator() {
foreach ($this->array as $value) {
yield $value['key1'] . '_' . $value['key2'] => $value['count'];
}
}
}
然后你可以这样做:
$myNewArray = new MyNewArrayIterator($myExistingArray);
foreach($myNewArray as $key => $value) {
echo $key . ": " . $value;
}
这在您的用例中可能有用,也可能没用。