1

オブジェクト内のネストされたプロパティのドット区切りパスを「解決」する関数を作成しようとしています。

次のオブジェクトがあるとします。

var obj = {
    A: {
        A_1: {
        },
        A_2: {
            A_2_a: {},
            A_2_b: {
                A_2_b_1: {},
                A_2_b_2: {},
            }
        },
        A_3: {},
    },
    B: {
        B_1: {
        },
        B_2: {
            B_2_a: {
            },
            B_2_b: {
                B_2_b_1: {},
                B_2_b_2: {},
            }
        },
        B_3: {},
    },
};

オブジェクトの関数を次のように呼び出してresolve(obj, "B_2_b_2")、プロパティへの完全なオブジェクトパスを返すようにしますB.B_2.B_2_b.B_2_b_2

4

2 に答える 2

1

サンプルオブジェクトのように、命名規則を想定します。

function resolve(id) {
    var parts = id.split("_");
    var path = [];
    for (var i=0; i<parts.length; i++)
        path.push(parts.slice(0, i+1).join("_"));
    return path;
}

> resolve("B_2_b_2")
["B", "B_2", "B_2_b", "B_2_b_2"]
> resolve("B_2_b_2").join(".")
"B.B_2.B_2_b.B_2_b_2"

パス配列を使用すると、ネストされたオブジェクトを簡単に再帰してプロパティ値を取得できます。


データ オブジェクトのツリー検索は簡単です。ただし、命名規則を想定することでそれを最適化できます。

function resolve(obj, id) {
    if (id in obj)
        return [id]; // we've found it
    var path;
    for (var l=id.length-1; l>0; l--) {
        var sub = id.substr(0, l);
        if (sub in obj && (path = resolve(obj[sub], id))) {
            path.unshift(sub);
            return path;
        }
    }
    for (var prop in obj) {
       if (path = resolve(obj[prop], id)) {
            path.unshift(prop);
            return path;
        }
    }
    return null;
}
于 2013-02-04T20:21:10.160 に答える
1

ユーレカ!私はそれを考え出した!以下の回答は、私が書いているライブラリの形式ですが、比較的簡単に理解できるはずです。

結局のところ、(私が知る限り)最善の方法は、最初に別の関数を使用して、すべてのプロパティ パスを含むターゲット オブジェクトからオブジェクトを構築することです。

/**
 * Returns an object containing all of the property paths of an object. Each
 * property path is referenced by the property name.
 * @param {object} The object to target
 * @return {object} Object containing paths ELSE undefined
 */
paths: function( obj, path, lastKey, nextKey ) {
    var o, key,
        path = path ? path : {},
        lastKey = lastKey ? lastKey : "",
        nextKey = nextKey ? nextKey : "";

    for ( o in obj ) {      

        // Push path onto stack
        path[o] = (nextKey + "." + lastKey + "." + o).replace(/^[.]+/g, "");

        // Pass updated "nextKey" along with next recurse
        key = nextKey + "." + lastKey;

        // Call again on all nested objects
        if ( (lib).isPlainObject(obj[o]) ) {
            (lib).paths(obj[o], path, o, key);
        }
    }

    return (lib).len(path) ? path : undefined;
},

次に、 resolve メソッドを paths メソッドの「ラッパー」として使用し、対象のプロパティ キーの名前空間を返します。

resolve: function( obj, key ) {     
    return (lib).paths(obj)[key];
},

上に最初に投稿したオブジェクトを使用します。

var res = o.resolve(obj, "A_2_b_1");
// Returns "A.A_2.A_2_b.A_2_b_1"

参考までに、このpathsメソッドは次のようなオブジェクトを返します。

// {
    // A: [...]
    // A_1: [...]
    // A_2: [...]
    // A_2_a: [...]
    // A_2_b: [...]
    // A_2_b_1: [
    //  0: "A_2_b_1"
    //  1: "A.A_2.A_2_b.A_2_b_1"
    // ]
    // A_2_b_2: [...]
    // A_2_c: [...]
    // A_3: [...]
    // B: [...]
    // ...
// }

各プロパティがオブジェクト内のパスにマップされる場所。

于 2013-02-04T22:06:04.513 に答える