在PHP中计算和构造唯一数组的更好方法

在PHP中计算和构造唯一数组的更好方法,php,Php,我有下面的代码,它需要花费相当长的时间来执行。有时它甚至会超时 foreach ($totalownerships as $totalownership) { if (!in_array($totalownership['titleno'], $totaltitles)) { $result['totalowns'] += 1; $totaltitles[] = $totalownership['titleno']; $result['ow

我有下面的代码,它需要花费相当长的时间来执行。有时它甚至会超时

foreach ($totalownerships as $totalownership) {
    if (!in_array($totalownership['titleno'], $totaltitles)) {
        $result['totalowns'] += 1;
        $totaltitles[] = $totalownership['titleno'];
        $result['ownershipid'] = $result['ownershipid'] . " " .$totalownership['titleno'];
    }
}

$totalownerships
数组大小为
52225
。有没有更好的方法来编写此代码,这样执行起来就不会花费很长时间?

使用PHP的快速内置数组操作工具来消除循环中的数组搜索,速度会快得多:

// Add all titles to $totaltitles, for added speed
foreach ($totalownerships as $totalownership) {
    $totaltitles[] = $totalownership['titleno'];
}

// For PHP 5.5+ you can use array_column() to get just the titleno field
//$totaltitles = array_column($totalownership, 'titleno');

// Use array_unique() to eliminate duplicate titles from $totaltitles
array_unique($totaltitles);

// Use count() to get a total count of $totaltitles
$result['totalowns'] = count($totaltitles);

// Use implode() for concatenation of title names
$result['ownershipid'] .= " " . implode(" ", $totaltitles);

有关更多PHP性能提示,请查看:

这将大大加快速度,使用PHP的快速内置数组操作工具消除循环中的数组搜索:

// Add all titles to $totaltitles, for added speed
foreach ($totalownerships as $totalownership) {
    $totaltitles[] = $totalownership['titleno'];
}

// For PHP 5.5+ you can use array_column() to get just the titleno field
//$totaltitles = array_column($totalownership, 'titleno');

// Use array_unique() to eliminate duplicate titles from $totaltitles
array_unique($totaltitles);

// Use count() to get a total count of $totaltitles
$result['totalowns'] = count($totaltitles);

// Use implode() for concatenation of title names
$result['ownershipid'] .= " " . implode(" ", $totaltitles);

要了解更多PHP性能提示,请选中:

而不是在数组操作中使用
O(n)
,我将使用
O(1)
keylook-up:

$totaltitles = array();
foreach ($totalownerships as $totalownership) {
    if (!isset($totaltitles[$totalownership['titleno']])) {
        $totaltitles[$totalownership['titleno']] = $totalownership['titleno'];
        $result['ownershipid'] .= " " . $totalownership['titleno'];
    }
}
$result['totalowns'] = count($totaltitles);
基本上,这个想法是将您的唯一属性用作数组键,这样您就可以使用恒定时间查找而不是线性查找


如果你想走一条(可能慢一点)更漂亮的路线,你可以试试:

$uniques = array_unqiue(array_map(function($own) { 
    return $own['titleno']; 
}, $totalownerships));
$result = array(
    'ownershipid' => implode(' ', $uniques), 
    'totalowns' => count($uniques)
);

(正如Steven Moseley所说,如果您使用的是PHP5.5,那么可以使用array\u column而不是array\u map调用。)

在数组操作中使用
O(n)
,我会使用
O(1)
键查找:

$totaltitles = array();
foreach ($totalownerships as $totalownership) {
    if (!isset($totaltitles[$totalownership['titleno']])) {
        $totaltitles[$totalownership['titleno']] = $totalownership['titleno'];
        $result['ownershipid'] .= " " . $totalownership['titleno'];
    }
}
$result['totalowns'] = count($totaltitles);
基本上,这个想法是将您的唯一属性用作数组键,这样您就可以使用恒定时间查找而不是线性查找


如果你想走一条(可能慢一点)更漂亮的路线,你可以试试:

$uniques = array_unqiue(array_map(function($own) { 
    return $own['titleno']; 
}, $totalownerships));
$result = array(
    'ownershipid' => implode(' ', $uniques), 
    'totalowns' => count($uniques)
);


(正如Steven Moseley所说,如果您使用的是PHP5.5,那么可以使用array\u column而不是array\u map调用。)

最好将其存储在数据库中并查询它。更快更简单。将
$totaltitles
转换为哈希而不是字典<与检查散列中是否存在密钥相比,_数组中的code>速度较慢。$totalownerships从何而来?如果它来自数据库,也许您应该检查查询以仅获取所需的行,这样以后就不需要对其进行筛选。@lracicot它们不是重复的,我无法从数据库端消除它们。最好将其存储在数据库中并进行查询。更快更简单。将
$totaltitles
转换为哈希而不是字典<与检查散列中是否存在密钥相比,_数组中的code>速度较慢。$totalownerships从何而来?如果它来自一个数据库,也许你应该检查你的查询,只获取你需要的行,这样你以后就不需要过滤它了。@lracicot它们不是重复的,我不能从数据库端消除它们。PS-编辑
for
循环回
foreach
-尽管这似乎不是你最大的性能损失,根据(注意答案1上的基准点)PS,foreach似乎是其中速度最快的一个-编辑了
for
循环回
foreach
-尽管这似乎不是您最大的性能打击,但根据(注意答案1上的基准点),foreach似乎是其中速度最快的一个+1因为降低操作的复杂性总是一个好主意。不幸的是,在这种情况下,它仍然是一个
O(n)
操作,因为
isset()
随着
$totaltitles
变大而变慢。它仍然会比OP的代码快。良好的创造性思维@StevenMoseley我不是说总的来说它变成了O(1)。有一个明显的问题&Omega;(n) 因为每个元素必须至少处理一次,所以在整个操作中。我的意思是线性in_数组操作可以替换为常数时间哈希表查找。我想我应该说得更清楚一点,整体操作是从二次到线性的@StevenMoseley更清楚一点:isset()是常数时间<代码>$totaltitles[$totalownership['titleno']]是固定时间。因此,
在本例中,不幸的是,它仍然是一个O(n)操作,因为随着$totaltitles变大,isset()变慢
是错误的。仍然是O(n),因为O(1)操作执行了n次。(别忘了原来的是O(n^2)——通过删除O(n)操作,将isset从in_数组更改为O(n)数组)您确定它是常数时间吗?它不会随着阵列的增长而变慢吗?你有一个基准吗?它肯定不是线性的(意味着一个非关联的容器,比如链表或普通数组上的线性搜索)。它可能是一个有序的树(可能是一个平衡的树,比如红黑树或AVL树)或者是一个散列图(我相信它是这样的)。是一个相当不完美的基准(基准中的非确定性让我哭泣,但我害怕缓存),但它足以证明它绝对是常数时间(这很奇怪,因为手册中暗示了一个平衡树)。+1因为尝试降低操作复杂性总是一个好主意。不幸的是,在这种情况下,它仍然是一个
O(n)
操作,因为
isset()
随着
$totaltitles
变大而变慢。它仍然会比OP的代码快。良好的创造性思维@StevenMoseley我不是说总的来说它变成了O(1)。有一个明显的问题&Omega;(n) 因为每个元素必须至少处理一次,所以在整个操作中。我的意思是线性in_数组操作可以替换为常数时间哈希表查找。我想我应该说得更清楚一点,整体操作是从二次到线性的@StevenMoseley更清楚一点:isset()是常数时间<代码>$totaltitles[$totalownership['titleno']]是固定时间。因此,
在本例中,不幸的是,它仍然是一个O(n)操作,因为随着$totaltitles变大,isset()变慢
是错误的。仍然是O(n),因为O(1)操作执行了n次。(别忘了原来的是O(n^2)——通过删除O(n)操作,将isset从in_数组更改为O(n)数组)您确定它是常数时间吗?这不可能