Поиск ключа и возвращаемого значения во вложенном объекте - PullRequest
0 голосов
/ 12 сентября 2018

Допустим, мой объект выглядит следующим образом. Это смесь разных массивов и родителей, без иерархического порядка. например,

"person": {
"id": 12345,
"name": "John Doe",
"emergencyContacts": [
  {
    "name": "Jane Doe",
    "phone": "888-555-1212",
    "relationship": "spouse",
    "moreDetails": {
      "id": 12345,
      "phones": {},
      "home": "800-123-4567",
      "mobile": "877-123-1234"
    }
  },
  {
    "name": "Justin Doe",
    "phone": "877-123-1212",
    "relationship": "parent",
    "mobile": "877-123-1234"
  }
],
"workContacts": [
  {
    "name": "Jane Doe",
    "phone": "888-555-1212",
    "relationship": "spouse",
    "moreworkDetails": {
      "id": 12345,
      "phones": {},
      "home": "800-123-4567",
      "mobile": "877-123-1234"
    }
  },
  {
    "name": "Justin Doe",
    "phone": "877-123-1212",
    "relationship": "parent",
    "mobile": "877-123-1234"
  }
]
}

Я хочу иметь возможность искать весь объект person и возвращать значение ключа mobile. Я предполагаю, что объект должен быть сплющен и создан новый массив со списком «уникальных» мобильных номеров, например,

var mobile = { 
0: 888-555-1212,
1: 800-123-4567,
2: 877-123-1234,
3: 083-111-3346
}

Я искал решения в чистом формате js и lodash, однако каждый найденный знает, как называется родитель и глубина массива - допустим, что родитель и глубина могут быть безграничны (это исключает его из вопроса Найти ключом во вложенном объекте ). Любая помощь будет высоко ценится. Спасибо

Ответы [ 4 ]

0 голосов
/ 12 сентября 2018
 returnValuesForAttribute = (attr) => {
    let mobile = {};
    let index = 0;
    Object.values(person).map(first_level => {
        if (Array.isArray(first_level)) {
            first_level.map(el => {
                if (Object.keys(el).includes(attr)) {
                    mobile[index] = el[attr];
                    index++;
                }
                Object.values(el).map(second_level => {
                    if (typeof second_level === 'object' && second_level[attr]) {
                        mobile[index] = second_level[attr];
                        index++;
                    }
                })
            })
        }
    });
    return mobile;
}
returnValuesForAttribute('mobile');

Выход: {0: "877-123-1234", 1: "877-123-1234", 2: "877-123-1234", 3: "877-123-1234"}

0 голосов
/ 12 сентября 2018

Вам не нужна рекурсия.Вы можете сделать это с помощью while loop:

function searchFor(what, where) {
  const stack = [where];
  const result = [];
  while (stack.length) {
    const item = stack.pop();
    if (Array.isArray(item)) {
      item.forEach(el => stack.push(el));
      continue;
    }
    if (item && typeof item === "object")
      Object.entries(item).forEach(([key, value]) =>
        key === what ?
          result.push(value) :
          stack.push(value)
      )
  }
  return result;
}
0 голосов
/ 12 сентября 2018

Я немного обобщил его с помощью кода, бессовестно украденного из моей собственной библиотеки: goodcore

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

let obj = {
    "id": 12345,
    "name": "John Doe",
    "emergencyContacts": [{
        "name": "Jane Doe",
        "phone": "888-555-1212",
        "relationship": "spouse",
        "moreDetails": {
          "id": 12345,
          "phones": {},
          "home": "800-123-4567",
          "mobile": "877-123-1234"
        }
      },
      {
        "name": "Justin Doe",
        "phone": "877-123-1212",
        "relationship": "parent",
        "mobile": "877-123-1234"
      }
    ],
    "workContacts": [{
        "name": "Jane Doe",
        "phone": "888-555-1212",
        "relationship": "spouse",
        "moreworkDetails": {
          "id": 12345,
          "phones": {},
          "home": "800-123-4567",
          "mobile": "877-123-1236"
        }
      },
      {
        "name": "Justin Doe",
        "phone": "877-123-1212",
        "relationship": "parent",
        "mobile": "877-123-1235"
      }
    ]
  };

function isObject(it) {
    return it !== null && typeof it === "object";
}
function isArray(it) {
    return Array.isArray ? Array.isArray(it) : Object.prototype.toString.call(it) === "[object Array]";
}
function forEach(target, fn) {
    if(isArray(target)) {
        target.forEach(fn);
    } else {
        Object.entries(target).forEach(([key, value]) => fn(value, key));
    }
}
function objReduce(obj, fn, acc) {
    let a = acc;
    forEach(obj, (value, key) => {
        if(isObject(value) || isArray(value)) {
            a = objReduce(value, fn, a);
        } 
        a = fn(a, value, key);
    });
    return a;
}

objReduce(obj, (acc, cur, key) => {
    if(key === "mobile") {
        acc.push(cur);
    }
    return acc;
}, []);

По сути, он создает функцию уменьшения объекта, которая перебирает все свойства и запускает на ней функцию-накопитель, как Array.prototype.reduce для массивов.Ему нужно немного кода, поскольку он обрабатывает массивы и объекты произвольно.

0 голосов
/ 12 сентября 2018

Вам понадобится рекурсивная функция.Для объяснения, пожалуйста, проверьте комментарии

let person = {
  "id": 12345,
  "name": "John Doe",
  "emergencyContacts": [{
      "name": "Jane Doe",
      "phone": "888-555-1212",
      "relationship": "spouse",
      "moreDetails": {
        "id": 12345,
        "phones": {},
        "home": "800-123-4567",
        "mobile": "877-123-1234"
      }
    },
    {
      "name": "Justin Doe",
      "phone": "877-123-1212",
      "relationship": "parent",
      "mobile": "877-123-1234"
    }
  ],
  "workContacts": [{
      "name": "Jane Doe",
      "phone": "888-555-1212",
      "relationship": "spouse",
      "moreworkDetails": {
        "id": 12345,
        "phones": {},
        "home": "800-123-4567",
        "mobile": "877-123-1236"
      }
    },
    {
      "name": "Justin Doe",
      "phone": "877-123-1212",
      "relationship": "parent",
      "mobile": "877-123-1235"
    }
  ]
}
let arrys = [];

//iterate the object 
function recursive(obj, key) {
  //iterate the object
  for (let keys in obj) {
    // check if the key name is same as the desired one
    if (keys === key) {
      // then push the value to an array
      arrys.push(obj[keys])

    } else {
      // if the value of a key is an array & if it is not empty
      if (Array.isArray(obj[keys]) && obj[keys].length > 0) {
        // iterate the array. in each iteration you will get the object
        // example emergencyContacts. In each iteration 
        // call the same function with new data 
        obj[keys].forEach(function(item) {
          // pass that object to the same function
          recursive(item, key)
        })

      }
      // if the value is an object then again call the same function 
      else if (typeof obj[keys] === 'object') {
        recursive(obj[keys], key)
      }
    }
  }
}

recursive(person, 'mobile');
//create object from the array
let newObj = {}
for (let m = 0; m < arrys.length; m++) {
  newObj[m] = arrys[m]

}
console.log(newObj)
...