类似于array_search_all的东西 - 替换数组中值的所有实例

时间:2017-02-21 15:31:07

标签: php arrays

鉴于这些数组:

// 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值。

2 个答案:

答案 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')))