如何存储对称矩阵表的数据?

时间:2018-08-02 18:35:26

标签: javascript matrix

我会尽力解释我的问题。我需要以与矩阵表类似的方式存储一些数据,但要添加代码。

让我们以一个简单的表格为例:

enter image description here

为此,我的第一个想法是创建一个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中使用它,以防万一它有很大的不同。

1 个答案:

答案 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";