Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

160
Visualizações
Find path to ALL matching key values in nested object

I have a function that gets me the path to the first finding of a nested object where the key and the value matches.

function getPath(obj, givenKey, givenValue) {
    for(var key in obj) {                                   
        if(obj[key] && typeof obj[key] === "object") {      
            var result = getPath(obj[key], givenValue, givenKey);
            if(result) {                                    
                result.unshift(key)
                return result;                              
            }
        } else if(obj[key] === givenValue && key === givenKey ) {
            return [key];
        }   
    }
}

sample data

var myObj = [
{
    "name": "needle",
    "children": [
    {
        "name": "group2",
        "children": [
        {
            "name": "item0"
        }]
    }]
},
{
    "name": "item1"
},
{
    "name": "needleGroup",
    "children": [
    {
        "name": "needleNestedGroup",
        "children": [
        {
            "name": "item3"
        },
        {
            "name": "needleNestedDeeperGroup",
            "children": [
            {
                "name": "needle"
            }]
        }]
    }]
}];

expected output

getPath(myObj, "name", "needle"):
      [0, "name"]
      ["2","children","0","children","1","children","0","name"]

However, I have now an object that contains these key-values multiple times, so I have multiple matches.

How can I get all of them in an array? My current function is just stopping after it finds the first match. The fact, that it's recursive makes things very complicated for me

about 4 years ago · Juan Pablo Isaza
2 Respostas
Responde à pergunta

0

I would write this atop a more generic findAllPaths function that accepts a predicate and finds the paths of all nodes in the object that match that predicate. With that, then findPathsByName is as simple as (target) => findAllPaths (({name}) => name == target).

In turn, I build findAllPaths on pathEntries, variants of which I use all the time. This function turns an object into an array of path/value pairs. Some versions only generate the leaf nodes. This one generate it for all nodes, including the root (with an empty path.) The basic idea of this function is to turn something like:

{a: 'foo', b: {c: ['bar', 'baz'], f: 'qux'}}

into this:

[
  [[], {a: 'foo', b: {c: ['bar', 'baz'], f: 'qux'}}], 
  [['a'], 'foo'], 
  [['b'], {c: ['bar', 'baz'], f: 'qux'}], 
  [['b', 'c'], ['bar', 'baz']], 
  [['b', 'c', 0], 'bar'], 
  [['b', 'c', 1], 'baz'], 
  [['b', 'f'], 'qux']
]

where the first item in every subarray is a path and the second a reference to the value at that path.

Here is what it might look like:

const pathEntries = (obj) => [
  [[], obj],
  ...Object (obj) === obj
    ? Object .entries (obj) .flatMap (
        ([k, x]) => pathEntries (x) .map (
          ([p, v]) => [[Array .isArray (obj) ? Number (k) : k, ... p], v]
        )
      )
    : []
]

const findAllPaths = (predicate) => (o) =>
  [...pathEntries (o)] .filter (([p, v]) => predicate (v, p)) .map (([p]) => p)

const findPathsByName = (target) => findAllPaths (({name}) => name == target)

const myObj = [{name: "needle", children: [{name: "group2", children: [{name: "item0"}]}]}, {name: "item1"}, {name: "needleGroup", children: [{name: "needleNestedGroup", children: [{name: "item3"}, {name: "needleNestedDeeperGroup", children: [{name: "needle"}]}]}]}]

console .log (findPathsByName ('needle') (myObj))
.as-console-wrapper {max-height: 100% !important; top: 0}

The question asked for string values for the array indices. I prefer the integer values myself as done here, but you simplify the function a bit:

-          ([p, v]) => [[Array .isArray (obj) ? Number (k) : k, ... p], v]
+          ([p, v]) => [[k, ... p], v]
about 4 years ago · Juan Pablo Isaza Relatório

0

Instead of returning the value, you could push it to an array and keep iterating.

At the end of the function, you return the array.

function getPath(obj, givenKey, givenValue) {
  let matches = [];
  for (var key in obj) {
    if (obj[key] && typeof obj[key] === "object") {
      var result = getPath(obj[key], givenValue, givenKey);
      if (result) {
        result.unshift(key)
        matches.push(...result);
      }
    } else if (obj[key] === givenValue && key === givenKey) {
      matches.push(key);
    }
  }
  
  return matches;
}

about 4 years ago · Juan Pablo Isaza Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda