Обрезать JSON до заданной цели и получить все родительские ключи - PullRequest
0 голосов
/ 05 января 2019

Я хочу получить доступ ко всем родителям данного целевого ключа например, я хочу дать macbook_pro и получить что-то вроде этого: ['electronics', 'computers', 'mac']

let testData = {

        cars : {

            sedan : {
                toyota : 'value1',
                kia : 'value2',
                mercedes : 'value3'
            },

            compact : {
                bugatti : 'value1',
                bugatti : 'value1',
            }

        },

        electronics : {

            computers : {
                mac : {
                    macbook_pro : "value 1 1",
                    macbook_air : "value 1 1"
                },
                pcs : 'value2'
            },

            mobiles : {
                apple : 'value',
                samsung : 'value'
            }
        }

    };

Я пытался написать рекурсивную функцию, чтобы получить все ключи. Это работает, но также возвращает все ключи других узлов.

let keys = [];
function collectKeys(obj, breakKey){
    for (let key in obj){
        if (typeof obj[key] === 'object' && obj[key].constructor === Object){
            keys.push(key);
            collectKeys(obj[key], breakKey);
        }
        if (key === breakKey){
            break;
        }
    }
}

Ответы [ 3 ]

0 голосов
/ 05 января 2019

Вы можете использовать эту рекурсивную функцию:

function getPath(obj, key) {
    if (Object(obj) !== obj) return; // It's a primitive value: No match
    if (key in obj) return []; // found it!
    for (let prop in obj) {
        const path = getPath(obj[prop], key);
        if (path) return [prop, ...path];
    }
}

const testData = {cars: {sedan: {toyota: 'value1',kia: 'value2',mercedes: 'value3'},compact: {bugatti: 'value1'}},electronics: {computers: {mac: {macbook_pro: 'value 1 1',macbook_air: 'value 1 1'},pcs: 'value2'},mobiles: {apple: 'value',samsung: 'value'}}};
console.log(getPath(testData, "pcs"));

Проблема в вашем коде заключается в том, что вы делаете keys.push(key); в то время, когда он не уверен, что текущий путь приведет к совпадению. Если рекурсивный вызов не находит соответствия, тогда этот ключ должен быть снова извлечен из keys.

Поскольку ваша функция ничего не возвращает, вы действительно не знаете, нашел ли рекурсивный вызов совпадение или нет, но это то, что вам нужно.

0 голосов
/ 05 января 2019

Сократить JSON до заданной цели и получить все родительские ключи

Я нашел эту проблему очень интересной и попытался (модульно) решить ее с помощью рекурсии следующим образом.

Здесь только getParentKeys () вернет вам ожидаемый результат, как вы хотите.

Другие функции - просто помощники (вызываемые) или независимые.

Просто пройдите код, начиная с функции testcase () , которая является стартовой.

function getAllMatchedKeys(testData, searchWord) {
    let type = Object.prototype.toString.call(testData).slice(8, -1) // Array, Object, String, Number
    let arr = [];

    if(type == 'Object') { // If it is object
        let keys = Object.keys(testData);

        for(let key of keys) {
            if(key === searchWord) {
                arr.push(key);
                return arr;
            }

            if(Object.prototype.toString.call(testData[key]).slice(8, -1) === 'Object') {
                arr = getAllMatchedKeys(testData[key], searchWord);

                if(arr.length !== 0) {
                    arr.push(key)
                    return arr;
                }
            }
        }
    }

    return arr;
}


function getKeys(testData, searchWord) {
    let allKeys = getAllMatchedKeys(testData, searchWord);
    let parentKeys = allKeys.slice(1).reverse();

    let keys = {
        allKeys: allKeys,
        parentKeys: parentKeys
    };

    return keys;
}


function getParentKeys(testData, searchWord) {
    /*
        Returns the parent keys, excluing the search word
    */

    let keys = getKeys(testData, searchWord);
    return keys["parentKeys"];
}


function testcase() {
    /*
        Test cases 
    */

    let testData = {
        cars: {
            sedan: {
                toyota: 'value1',
                kia: 'value2',
                mercedes: 'value3'
            },
            compact: {
                bugatti: 'value1'
            },
            toyota: {
                car1: 'car-1',
                car2: 'car-2',
                car3: {
                    redbull: 'favourite'
                }
            }
        },
        electronics: {
            computers: {
                mac: {
                    macbook_pro: "value 1 1",
                    macbook_air: "value 1 2"
                },
                pcs: 'value2'
            },
            mobiles: {
                apple: "value",
                samsung: "value"
            }
        }
    };

    // TEST CASE 1
    let macbookAllKeys = getKeys(testData, 'macbook_pro'); // Object
    /*
        { allKeys: [ 'macbook_pro', 'mac', 'computers', 'electronics' ],
          parentKeys: [ 'electronics', 'computers', 'mac' ] }
    */

    // Pretty printing
    console.log(JSON.stringify(macbookAllKeys, null, 4));
    /*
        {
            "allKeys": [
                "macbook_pro",
                "mac",
                "computers",
                "electronics"
            ],
            "parentKeys": [
                "electronics",
                "computers",
                "mac"
            ]
        }
    */

    let macbookParentKeys = getParentKeys(testData, 'macbook_pro');
    console.log(macbookParentKeys); /* [ 'electronics', 'computers', 'mac' ] */

    // TEST CASE 2
    let kiaParentKeys = getParentKeys(testData, 'kia');
    console.log(kiaParentKeys); /* [ 'cars', 'sedan' ] */

    // TEST CASE 3 (I added extra keys to your testData for this)
    let redbullParentKeys = getParentKeys(testData, 'redbull');
    console.log(redbullParentKeys); /* [ 'cars', 'toyota', 'car3' ] */


    // TEST CASE 4 
    let sedanParentKeys = getParentKeys(testData, 'sedan');
    console.log(sedanParentKeys); /* [ 'cars' ] */
}

// Start
testcase();
0 голосов
/ 05 января 2019

Я нашел путь, используя алгоритм рекурсивного обхода дерева.

const testData = {
    cars: {
        sedan: {
            toyota: 'value1',
            kia: 'value2',
            mersedes: 'value3'
        },
        compact: {
            bugatti: 'value4'
        }
    },
    electronics: {
        computers: {
            mac: {
                macbook_pro: 'value5',
                macbook_air: 'value6'
            },
            pcs: 'value7'
        },
        mobiles: {
            apple: 'value8',
            samsung: 'value9'
        }
    }
};

function getPath(dataObject, value) {
    let foundPath;

    function collectKeys(data, path = []) {
        Object.keys(data).forEach(key => {
            if (key === value) {
                foundPath = path;
                return;
            }
            if (typeof data[key] !== 'string') {
                collectKeys(data[key], path.concat([key]));
            }
        });
    }

    collectKeys(dataObject);
    return foundPath;
}

console.log((getPath(testData, 'sedan')).join(',') === ['cars'].join(','));
console.log((getPath(testData, 'macbook_pro')).join(',') === ['electronics', 'computers', 'mac'].join(','));
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...