Vector
概述
Ds\Vector 是一个有序的连续值序列,类似于 PHP 原生索引数组,但具有更好的内存局部性和性能优势。Vector 使用连续内存存储,支持 O(1) 的索引访问和末尾操作。
基础概念
特性
| 特性 | 说明 |
|---|---|
| 有序 | 元素按插入顺序排列 |
| 自动索引 | 从 0 开始的整数索引 |
| 连续内存 | 类似 C 数组的内存布局 |
| 类型安全 | 值可以是任意类型 |
| 可序列化 | 支持 toArray() 和 jsonSerialize() |
时间复杂度
| 操作 | 复杂度 |
|---|---|
get($index) | O(1) |
set($index, $value) | O(1) |
push(...$values) | O(1) 摊还 |
pop() | O(1) |
insert($index, ...$values) | O(n) |
remove($index) | O(n) |
shift() / unshift() | O(n) |
语法与代码
创建 Vector
php
<?php
declare(strict_types=1);
use Ds\Vector;
// 从数组创建
$vector = new Vector([1, 2, 3, 4, 5]);
// 空向量
$empty = new Vector();
// 从其他集合创建
$set = new \Ds\Set([1, 2, 3]);
$vector = new Vector($set->toArray());基本操作
php
<?php
declare(strict_types=1);
use Ds\Vector;
$vector = new Vector(['a', 'b', 'c']);
// 读取
echo $vector->get(0); // a
echo $vector->get(-1); // c(负索引,PHP 8.0+)
echo $vector->first(); // a
echo $vector->last(); // c
// 修改
$vector->set(1, 'B');
echo $vector->get(1); // B
// 追加
$vector->push('d', 'e');
// ['a', 'B', 'c', 'd', 'e']
// 移除末尾
$vector->pop(); // 移除 'e'
// 统计
echo $vector->count(); // 4
echo $vector->isEmpty(); // false插入与删除
php
<?php
declare(strict_types=1);
use Ds\Vector;
$vector = new Vector([1, 2, 3, 4, 5]);
// insert - 在指定位置插入
$vector->insert(2, 10, 20);
// [1, 2, 10, 20, 3, 4, 5]
// remove - 移除指定位置
$vector->remove(2);
// [1, 2, 20, 3, 4, 5]
// shift - 移除第一个
$vector->shift();
// [2, 20, 3, 4, 5](O(n) 操作)
// unshift - 在开头插入
$vector->unshift(0);
// [0, 2, 20, 3, 4, 5](O(n) 操作)
// 清空
$vector->clear();查找与排序
php
<?php
declare(strict_types=1);
use Ds\Vector;
$vector = new Vector([3, 1, 4, 1, 5, 9, 2, 6]);
// contains - 是否包含值
echo $vector->contains(5); // true
echo $vector->contains(99); // false
// find - 查找值(返回键或 false)
$key = $vector->find(5);
echo $key; // 4
// sort - 原地排序
$sorted = $vector->copy();
$sorted->sort();
// [1, 1, 2, 3, 4, 5, 6, 9]
// reverse - 原地反转
$sorted->reverse();
// [9, 6, 5, 4, 3, 2, 1, 1]
// sorted - 返回排序后的新 Vector(不修改原 Vector)
$newVector = $vector->sorted();函数式操作
php
<?php
declare(strict_types=1);
use Ds\Vector;
$vector = new Vector([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
// map - 转换
$squared = $vector->map(fn(int $n): int => $n ** 2);
// [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
// filter - 筛选
$evens = $vector->filter(fn(int $n): bool => $n % 2 === 0);
// [2, 4, 6, 8, 10]
// reduce - 归约
$sum = $vector->reduce(fn(int $carry, int $n): int => $carry + $n, 0);
// 55
// join - 连接为字符串
$words = new Vector(['Hello', 'World', 'PHP']);
echo $words->join(', '); // Hello, World, PHP
// slice - 切片
$sliced = $vector->slice(2, 3);
// [3, 4, 5]toArray 与序列化
php
<?php
declare(strict_types=1);
use Ds\Vector;
$vector = new Vector([1, 2, 3]);
// toArray - 转为原生数组
$arr = $vector->toArray();
// [1, 2, 3]
// jsonSerialize - JSON 序列化
echo json_encode($vector);
// [1, 2, 3]
// copy - 创建副本
$copy = $vector->copy();
$copy->push(4);
echo $vector->count(); // 3(不受影响)详细说明
Vector vs 原生索引数组
php
<?php
declare(strict_types=1);
// Vector 的优势:
// 1. 内存连续,缓存友好
// 2. push/pop 是 O(1)(原生数组 array_push 也是 O(1))
// 3. shift/unshift 比 array_shift 快(但仍然是 O(n))
// 4. 提供丰富的函数式方法(map/filter/reduce)
// 5. 类型安全
// 劣势:
// 1. 需要安装 DS 扩展
// 2. 不支持字符串键
// 3. 不能直接 json_encode(需要 toArray)
// 4. 不支持 [] 语法使用建议
Vector 适合大量数据的顺序存储和函数式操作。如果只是简单的数组操作,原生数组足够。
实战示例
数据流处理
php
<?php
declare(strict_types=1);
use Ds\Vector;
class DataPipeline
{
private Vector $pipeline;
public function __construct(array $data)
{
$this->pipeline = new Vector($data);
}
public function filter(callable $callback): self
{
$this->pipeline = new Vector(
array_values(array_filter($this->pipeline->toArray(), $callback))
);
return $this;
}
public function map(callable $callback): self
{
$this->pipeline = new Vector(
array_map($callback, $this->pipeline->toArray())
);
return $this;
}
public function take(int $n): self
{
$this->pipeline = $this->pipeline->slice(0, $n);
return $this;
}
public function collect(): array
{
return $this->pipeline->toArray();
}
}
$result = (new DataPipeline(range(1, 100)))
->filter(fn(int $n): bool => $n % 3 === 0)
->map(fn(int $n): int => $n ** 2)
->take(5)
->collect();
print_r($result);
// [9, 36, 81, 144, 225]Vector 的迭代器
php
<?php
declare(strict_types=1);
use Ds\Vector;
$vector = new Vector(['a', 'b', 'c', 'd', 'e']);
// reverse 迭代
$reversed = $vector->copy()->reverse();
foreach ($reversed as $value) {
echo $value . ' ';
}
// e d c b a
// 使用 ArrayAccess 接口
echo $vector[0]; // a
echo $vector[4]; // e
isset($vector[2]); // true
isset($vector[10]); // false
// 遍历时修改(需要引用)
$vector = new Vector([1, 2, 3, 4, 5]);
foreach ($vector as $key => $value) {
$vector->set($key, $value * 10);
}
// [10, 20, 30, 40, 50]Vector 与原生数组互转
php
<?php
declare(strict_types=1);
use Ds\Vector;
// 原生数组 -> Vector
$native = [1, 2, 3, 4, 5];
$vector = new Vector($native);
// Vector -> 原生数组
$back = $vector->toArray();
// 在混合代码中使用
function processData(Vector $data): Vector
{
return $data->filter(fn(int $n): bool => $n > 2)
->map(fn(int $n): int => $n ** 2);
}
// 从原生数组调用
$result = processData(new Vector([1, 2, 3, 4, 5]))
->toArray();
// [9, 16, 25]选择 Vector 的场景
- 需要大量 push/pop 操作的有序数据
- 需要函数式链式操作(map/filter/reduce)
- 需要高性能的连续内存存储
- 数据量较大且频繁修改时
Vector 的 JSON 输出
php
<?php
declare(strict_types=1);
use Ds\Vector;
$vector = new Vector(['name' => 'Alice', 'scores' => [90, 85, 95]]);
// Vector 实现了 JsonSerializable
$json = json_encode($vector);
echo $json;
// ["name":"Alice","scores":[90,85,95]]
// 嵌套 Vector
$nested = new Vector([
new Vector([1, 2, 3]),
new Vector([4, 5, 6]),
]);
echo json_encode($nested);
// [[1,2,3],[4,5,6]]注意事项
越界访问
get() 越界时抛出 OutOfRangeException。使用前用 has() 或 offsetExists() 检查。
最佳实践
- 大数据量用 Vector:内存局部性好
- 函数式操作用 Vector:map/filter/reduce 链式调用
- 序列化用 toArray():JSON 输出前转换
- 越界检查用 contains/find:避免 get 越界
- copy 创建独立副本:需要保留原数据时