鉴于这些数组:
// an array of values
$target = [5, 10, 15, 5, 25];
// an array of objects, direct from database
// all "original" values in this array are unique (no duplicates)
$replacements = [{original: 5, replacement: 7}, {original: 15, replacement: 155}, ..etc...];
使用$target
数组中的替换值替换$replacement
中原始值的所有实例的最有效/最高效的方法是什么?期望的结果:
// note that BOTH instances of the value 5 were replaced...
$result = [7, 10, 155, 7, 25];
这就是我现在所拥有的,但并不是最佳:
foreach ( $replacements AS $sub ) {
// I hate assignments within conditions, but DO want performance
while ( FALSE !== ($index = array_search( $sub->original, $target ) ) ) {
$target[ $index ] = $sub->replacement;
}
}
注意:PHP版本为5.6
相关说明:
1. $target
数组可以包含5到30个值,但通常为10-15个值
2. $target
数组可能包含重复值
3. $replacements
数组可以包含1到8个对象,但通常是2或3个对象
4.对于$replacements
包含重复original
值的问题,我们不担心
5. $replacement
包含"级联"值。 (也就是说,不用担心一个对象用值7替换值5,然后用另一个值替换值7的另一个对象)。
性能受到关注的原因是,这可能会被称为几千次,具有不同的$target
和$replacement
值。
答案 0 :(得分:1)
有一些警告:如果5
将替换为7
,并且可能存在类似{original: 7, replacement: 15}
的对象 - 并且它将替换先前替换的值,在“非常”循环遍历中。
使用此{original: 5, replacement: 7}, {original: 7, replacement: 25}
- 当您希望5
成为7
时,它最终会成为25
。这可能是令人困惑和意外的循环。
以下应该是最佳解决方案之一(特别是如果$replacements
会有大量项目):
假设我们有以下replacement
集:
[{"original": 5, "replacement": 7}, {"original": 15, "replacement": 155},{"original": 25, "replacement": 27},{"original": 10, "replacement": 17},{"original": 15, "replacement": 255},{"original": 23, "replacement": 27},{"original": 17, "replacement": 17}]
使用附加数组($replaced_keys
)来累积已处理的密钥。
$target = [5, 10, 15, 5, 25];
$target_count = count($target);
$replaced_keys = [];
foreach ($replacements as $sub) {
while (false !== ($index = array_search($sub->original, $target))
&& !in_array($index, $replaced_keys)) {
$target[$index] = $sub->replacement;
$replaced_keys[] = $index;
}
// avoiding circular repalcements and redundant iterations at one go
if (count($replaced_keys) == $target_count) break;
}
print_r($target);
输出:
Array
(
[0] => 7
[1] => 17
[2] => 155
[3] => 7
[4] => 27
)
答案 1 :(得分:1)
姑且:
asort($target);
$previous_item = false;
$previous_replace = false;
foreach ($target as &$item) {
if ($item==$previous_item && $previous_replace!==false) {
$item = $previous_replace;
} else {
$previous_replace = false;
foreach ($replacements as $replacement) {
if ($item == $replacement->original) {
$previous_replace = $replacement->replacement;
$previous_item = $item;
$item = $previous_replace;
break;
}
}
}
}
ksort($target);
假设 $ target 的元素通常少于 $ replacementments 。 中断每次都会停止搜索所有替换,因为原件是唯一的。问题是,它比array_search慢。
将替换首先复制到数组中可能会更快,如果它相当大,并使用它来直接查找值(而不是内部foreach):
class City(db.Model):
__tablename__ = 'cities'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(255), unique=True)
class Street(db.Model):
__tablename__ = 'streets'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(255), unique=True)
修改强>
再考虑一下。由于您在 $ target 中有重复值,因此不能两次搜索替换值可能有一些优点:
db.Table('city_street',
db.Column('city_id', db.Integer(), db.ForeignKey('cities.id')),
db.Column('street_id', db.Integer(), db.ForeignKey('streets.id')))