我会尽力解释我的问题。我需要以与矩阵表类似的方式存储一些数据,但要添加代码。
让我们以一个简单的表格为例:
为此,我的第一个想法是创建一个JS对象,该对象存储如下所示的所有可能性:
const Y = 'Yellow';
const R = 'Red';
const W = 'White';
const P = 'Pink';
const data = {
Y: { Y: Y, R: Y, W: Y },
R: { Y: Y, R: R, W: P },
W: { Y: Y, R: P, W: W }
};
console.log(data['W']['R']); // 'Pink'
但是考虑到我将拥有更多可能性的事实,这显然无法维持。
我也可以像这样减小对象的大小,但是我再次担心很难维护:
const data = {
Y: { Y: Y, R: Y, W: Y },
R: { R: R, W: P },
W: { W: W }
};
问题听起来很简单,但我找不到其他存储此类数据的方法。有更好的方法吗?
此外,我想补充一点是,我在这里使用了JS,因为我对这种语言更加熟悉,但是我将不得不在PHP中使用它,以防万一它有很大的不同。
答案 0 :(得分:1)
最紧凑的表示形式是单个数组中的三角矩阵,除非您确实缺乏空间,否则我不建议这样做。
function triMatrix(n) { // not really needed
return new Array(n * (n + 1) / 2);
}
function trindex(row, col) {
if (col > row) {
var tmp = row; row = col; col = tmp;
}
return row * (row + 1) / 2 + col;
}
function triStore(tri, indexOfKey, rowKey, colKey, value) {
tri[trindex(indexOfKey[rowKey], indexOfKey[colKey])] = value;
}
function triGet(tri, indexOfKey, rowKey, colKey) {
return tri[trindex(indexOfKey[rowKey], indexOfKey[colKey])];
}
const keyOfIndex = ['Y', 'R', 'W'];
const indexOfKey = {'Y': 0, 'R': 1, 'W': 2}; // can be calculated
const N = keyOfIndex.length;
var tri = triMatrix(N); // could also be var tri = [];
triStore(tri, indexOfKey, 'Y', 'Y', 'Y');
triStore(tri, indexOfKey, 'Y', 'R', 'Y');
triStore(tri, indexOfKey, 'Y', 'W', 'Y');
triStore(tri, indexOfKey, 'R', 'R', 'R');
triStore(tri, indexOfKey, 'R', 'W', 'P');
triStore(tri, indexOfKey, 'W', 'W', 'W');
tri; // => [ "Y", "Y", "R", "Y", "P", "W" ]
triGet(tri, indexOfKey, 'R', 'W'); // => "P"
triGet(tri, indexOfKey, 'W', 'R'); // => "P"
要点是:您的矩阵是对称的,因此您只需要其上三角矩阵或下三角矩阵(包括对角线)。在您的建议中,您存储上三角矩阵,而在我中存储下三角矩阵,因为索引计算要简单得多。该数组将包含1个元素的第一行,2个元素的第二个,3个元素的第3个,依此类推。只需记住1 + 2 + ... + n = n(n + 1)/ 2,您就会了解计算数组索引。
M₀₀ M₀₁ M₀₂ M₀₀ T₀
M₁₀ M₁₁ M₁₂ => M₁₀ M₁₁ => T₁ T₂ => T₀ T₁ T₂ T₃ T₄ T₅
M₂₀ M₂₁ M₂₂ M₂₀ M₂₁ M₂₂ T₃ T₄ T₅
矩阵很容易扩展1行/列,不需要重新索引数组:
M₀₀ M₀₁ M₀₂ M₀₃ M₀₀ T₀
M₁₀ M₁₁ M₁₂ M₁₃ M₁₀ M₁₁ T₁ T₂
M₂₀ M₂₁ M₂₂ M₂₃ => M₂₀ M₂₁ M₂₂ => T₃ T₄ T₅ => T₀ ... T₆ T₇ T₈ T₉
M₃₀ M₃₁ M₃₂ M₃₃ M₃₀ M₃₁ M₃₂ M₃₃ T₆ T₇ T₈ T₉
作为练习,我将上面的内容大致翻译为PHP,这是您的目标语言。即使我一开始不建议使用“单个数组中的三角矩阵”方法,但是如果您的需求与您的需求相匹配,那么还是欢迎您使用以下类作为黑匣子(如果没有,也许我可以提供帮助)。
class SymmetricMatrix
{
private $n = 0;
private $triangular = [];
private $key_of_index = [];
private $index_of_key = [];
private function add_key_if_necessary($key) {
if ( !isset($this->index_of_key[$key])) {
$index = $this->n++;
$this->index_of_key[$key] = $index;
$this->key_of_index[$index] = $key;
for ($i = 0; $i < $this->n; $i++) {
$this->triangular[] = false; // avoid "jumping" index & init to "absent"
}
}
}
private static function trindex($row, $col) {
if ($col > $row) {
$tmp = $row; $row = $col; $col = $tmp;
}
return $row * ($row + 1) / 2 + $col;
}
public function put($key1, $key2, $value) {
$this->add_key_if_necessary($key1);
$this->add_key_if_necessary($key2);
$trindex = self::trindex($this->index_of_key[$key1], $this->index_of_key[$key2]);
$this->triangular[$trindex] = $value;
}
public function get($key1, $key2) {
if (!isset($this->index_of_key[$key1]) || !isset($this->index_of_key[$key2])) {
return false;
}
$trindex = self::trindex($this->index_of_key[$key1], $this->index_of_key[$key2]);
return $this->triangular[$trindex];
}
public function find_first($value) { // $value !== false
for ($row = 0; $row < $this->n; $row++) {
for ($col = 0; $col <= $row; $col++) {
$trindex = trindex($row, $col);
if ($this->triangular[$trindex] === $value) {
return [$this->key_of_index[$row], $this->key_of_index[$col]];
}
}
}
return false;
}
public function get_keys() {
return $this->key_of_index;
}
public function dump() {
var_export($this);
echo "\n";
}
}
$m = new SymmetricMatrix();
$m->put('Y', 'Y', 'Y');
$m->put('Y', 'R', 'Y');
$m->put('Y', 'W', 'Y');
$m->put('R', 'R', 'R');
$m->put('R', 'W', 'P');
$m->put('W', 'W', 'W');
$m->dump();
echo "keys: ", implode(', ', $m->get_keys()), "\n";
echo "m[R][W]: ", $m->get('R', 'W'), "\n";
echo "m[W][R]: ", $m->get('W', 'R'), "\n";