数组切片并保留键名

12

我面临保留键的数组拼接问题,因此编写了以下功能:
我通过将每个项目包装在数组中来解决问题,但似乎存在一些内存效率低下的语句。
你有什么想法吗?
谢谢。


array_splice_pk

array_splice不同,它可以保留键。

概览:

  • &$input -> 与array_splice相同。
  • $key -> 目标键。
  • $use_key_as_offset -> 使用$key参数作为数字偏移量
  • $length -> 与array_splice相同。
  • $replacement -> 与array_splice相同。但你也可以为每个值提供

代码:

function array_splice_pk(&$input, $key, $use_key_as_offset = false, $length = 0, $replacement = null) {
    if (!is_array($input) || !is_scalar($key)) {
        return array();
    }
    if ($replacement !== null) {
        $replacement = array($replacement);
        if (!is_array($replacement[0])) {
            $replacement = array($replacement);
        }
    }
    $wrapper = array();
    foreach ($input as $k => $v) {
        $wrapper[] = array($k => $v);
    }
    $del_key = null;
    foreach ($wrapper as $k => $v) {
        if ($use_key_as_offset) {
            if ($k === (int)$key) {
                $del_key = $k;
                break;
            }
        } else {
            if (key($v) == $key) {
                $del_key = $k;
                break;
            }
        }
    }
    if ($del_key === null) {
        return array();
    }
    if ($replacement === null) {
        $wrapper_ret = array_splice($wrapper, $del_key, $length);
    } else {
        $wrapper_ret = array_splice($wrapper, $del_key, $length , $replacement);
    }
    $ret = $input = array();
    foreach ($wrapper_ret as $wrap) {
        list($k, $v) = each($wrap);
        $ret[$k] = $v;
    }
    foreach ($wrapper as $wrap) {
        list($k ,$v) = each($wrap);
        $input[$k] = $v;
    }
    return $ret;
}

样例:

$arr1 = $arr2 = array(
    'one'   => 'test',
    'two'   => 'test',
    'three' => 'test',
    'four'  => 'test',
);
$ret1 = array_splice_pk($arr1, 'three', false, 1, array('fizz' => '!!!'));
$ret2 = array_splice_pk($arr2, 2      , true , 1, array('fizz' => '!!!'));

var_dump('Result1', $arr1, $ret1, 'Result2', $arr2, $ret2);

结果:

string(7) "Result1"
array(4) {
  ["one"]=>
  string(4) "test"
  ["two"]=>
  string(4) "test"
  ["fizz"]=>
  string(3) "!!!"
  ["four"]=>
  string(4) "test"
}
array(1) {
  ["three"]=>
  string(4) "test"
}
string(7) "Result2"
array(4) {
  ["one"]=>
  string(4) "test"
  ["two"]=>
  string(4) "test"
  ["fizz"]=>
  string(3) "!!!"
  ["four"]=>
  string(4) "test"
}
array(1) {
  ["three"]=>
  string(4) "test"
}

array_splice 确实会 保留字符串键。你只是使用字符串键。 array_splice 有什么问题? - deceze
2
@deceze 不行。http://ideone.com/TuMVcL - mpyw
1
哦,我的错。替换数组键确实没有被保留。虽然我想到了如果你使用关联数组,你可以使用 $replacement + $original 来覆盖或插入特定的键。如果你想要删除键,最好在单独的步骤中完成。通过数字位置用其他字符串键替换字符串键似乎是一种奇怪的操作。 - deceze
3个回答

9

我在array_slice函数的手册中找到了这个。

<?php
function array_splice_assoc(&$input, $offset, $length, $replacement = array()) {
    $replacement = (array) $replacement;
    $key_indices = array_flip(array_keys($input));
    if (isset($input[$offset]) && is_string($offset)) {
            $offset = $key_indices[$offset];
    }
    if (isset($input[$length]) && is_string($length)) {
            $length = $key_indices[$length] - $offset;
    }

    $input = array_slice($input, 0, $offset, TRUE)
            + $replacement
            + array_slice($input, $offset + $length, NULL, TRUE); 
}

 $fruit = array(
    'orange' => 'orange',
    'lemon' => 'yellow',
    'lime' => 'green',
    'grape' => 'purple',
    'cherry' => 'red',
 );

  // Replace lemon and lime with apple
  array_splice_assoc($fruit, 'lemon', 'grape', array('apple' => 'red'));

  // Replace cherry with strawberry
  array_splice_assoc($fruit, 'cherry', 1, array('strawberry' => 'red'));
  ?>

它似乎在保留键的同时更加节省空间和时间。


不错的函数!但第一个例子 array_splice_assoc($fruit, 'lemon', 'grape', array('apple' => 'red')); 看起来有些奇怪。这里的 'grape' 是什么意思? - mpyw
2
在编程上下文中,“till”可以被看作是“直到”的意思。它计算了从“grape”位置开始的长度。 - CodeTower

4
这里有一个函数,可以保留替换数组的键,并且与原始的array_splice函数具有相同的参数列表。
<?php

function array_splice_preserve_keys(&$input, $offset, $length=null, $replacement=array()) {
    if (empty($replacement)) {
        return array_splice($input, $offset, $length);
    }

    $part_before  = array_slice($input, 0, $offset, $preserve_keys=true);
    $part_removed = array_slice($input, $offset, $length, $preserve_keys=true);
    $part_after   = array_slice($input, $offset+$length, null, $preserve_keys=true);

    $input = $part_before + $replacement + $part_after;

    return $part_removed;
}

// use as normal
array_splice_preserve_keys($input, $offset, $length, $replacement);

请查看发布在https://github.com/lode/gaps上的内容。

你是不是指的是 array_splice 而不是 array_keys - Nick
感谢 @Nick 指出的笔误! - Lode
array_splice 似乎无法保留 $input 数字键。 - Vigintas Labakojis

2

我将在2022年用我的PHP 8知识发布自我答案。
它可以正确接受负长度/偏移和字符串偏移。

function array_splice_assoc(array &$input, int|string $key, ?int $length = null, $replacement = [], bool $use_int_key_as_offset = true): array
{
    // Normalize key/offset
    $offset = match (true) {
        is_string($key) || !$use_int_key_as_offset => array_flip(array_keys($input))[$key] ?? throw new OutOfBoundsException(),
        $key < 0 => count($input) + $key,
        default => $key,
    };

    // Normalize length
    $length = match (true) {
        $length === null => count($input) - $offset,
        $length < 0 => count($input) + $length - $offset,
        default => $length,
    };

    // Manipulate each part
    $before = array_slice($input, 0, $offset, true);
    $removed = array_slice($input, $offset, $length, true);
    $after = array_slice($input, $offset + $length, null, true);

    // Merge parts, allowing the latter overrides the former
    $input = array_replace($before, (array)$replacement, $after);

    return $removed;
}

示例:

$array = ['a' => 'A', 'b' => 'B', 3 => 'C', 4 => 'D'];

$original = $array;
$removed = array_splice_assoc($original, 1, 1, [5 => 'E']);
echo json_encode(compact('original', 'removed')) . PHP_EOL;
/*
{"original":{"a":"A","5":"E","3":"C","4":"D"},"removed":{"b":"B"}}
*/

$original = $array;
$removed = array_splice_assoc($original, 2, replacement: [5 => 'E']);
echo json_encode(compact('original', 'removed')) . PHP_EOL;
/*
{"original":{"a":"A","b":"B","5":"E"},"removed":{"3":"C","4":"D"}}
*/

$original = $array;
$removed = array_splice_assoc($original, -3, 1, [5 => 'E']);
echo json_encode(compact('original', 'removed')) . PHP_EOL;
/*
{"original":{"a":"A","5":"E","3":"C","4":"D"},"removed":{"b":"B"}}
*/

$original = $array;
$removed = array_splice_assoc($original, -3, -1, [5 => 'E']);
echo json_encode(compact('original', 'removed')) . PHP_EOL;
/*
{"original":{"a":"A","5":"E","4":"D"},"removed":{"b":"B","3":"C"}}
*/

$original = $array;
$removed = array_splice_assoc($original, 'b', 2, [5 => 'E']);
echo json_encode(compact('original', 'removed')) . PHP_EOL;
/*
{"original":{"a":"A","5":"E","4":"D"},"removed":{"b":"B","3":"C"}}
*/

$original = $array;
$removed = array_splice_assoc($original, 3, 1, [5 => 'E']);
echo json_encode(compact('original', 'removed')) . PHP_EOL;
/*
{"original":{"a":"A","b":"B","3":"C","5":"E"},"removed":{"4":"D"}}
*/

$original = $array;
$removed = array_splice_assoc($original, 3, 1, [5 => 'E'], false);
echo json_encode(compact('original', 'removed')) . PHP_EOL;
/*
{"original":{"a":"A","b":"B","5":"E","4":"D"},"removed":{"3":"C"}}
*/

太棒了!谢谢! - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接