3

I'm trying to turn a nested object that represents my file system into an array of strings that represent the file paths for each folder and file.

Input:

let obj = {
  'app': {
    'body': {
      'abs': {
        'muscles.txt': 1
      },
      'foot.js': 1,
      'hand.txt': 1,
      'leg.txt': 1
    },
    'cat.txt': 1,
    'dog.js': 1,
    'writing': {
      'pen.txt': 1,
      'phone.txt': 1
    }
  }
};

Output:

  [
  '/app', 
  '/app/body',
  '/app/body/abs/',
  '/app/body/abs/muscles.txt',
  '/app/body/foot.js',
  '/app/body/hand.txt',
  ...
]

What I have so far (it's not working):

function filePaths(obj, oldKey = '', store = []) {
  for (let key in obj) {
    if (typeof obj[key] === 'object') {
      store.push('/' + key);
      filePaths(obj[key], key, store);
    } else {
      store.push('/' + oldKey + '/' + key);
    }
  }
  return store;
}

filePaths(obj);
2
  • 2
    Your output has paths that sometimes have a trailing slash (/app/body/abs/) and sometimes not (/app, /app/body). Do you want the result with or without that slash, or is there another criteria by which to include it or not? Commented Aug 2, 2018 at 23:45
  • Yes, sorry, this is a mistake on my part. I wanted no trailing slash. thank you for your answer. Commented Aug 3, 2018 at 21:18

3 Answers 3

3

Here is a working version:

let obj = {
  'app': {
    'body': {
      'abs': {
        'muscles.txt': 1
      },
      'foot.js': 1,
      'hand.txt': 1,
      'leg.txt': 1
    },
    'cat.txt': 1,
    'dog.js': 1,
    'writing': {
      'pen.txt': 1,
      'phone.txt': 1
    }
  }
};

function filePaths(obj, prefix = '', store = []) {
  for (let key in obj) {
    const curPath = `${prefix}/${key}`;
    if (typeof obj[key] === 'object') {
      store.push(curPath);      
      filePaths(obj[key], curPath, store);
    } else {
      store.push(curPath);      
    }
  }
  return store;
}

console.log(filePaths(obj));

So I've kept most of your code, but changed the fact that while you kept the "old" key I keep the current path and it serves as a prefix for all the files and as a prefix for all the directories that will get the current key appended.

Sign up to request clarification or add additional context in comments.

1 Comment

Thank you Sylwester, I knew I was close, but my logic was slightly off.
1

Here's a recursive solution that leverages the Object.keys method with the spread operator, concat, and map:

let obj = {
  'app': {
    'body': {
      'abs': {
        'muscles.txt': 1
      },
      'foot.js': 1,
      'hand.txt': 1,
      'leg.txt': 1
    },
    'cat.txt': 1,
    'dog.js': 1,
    'writing': {
      'pen.txt': 1,
      'phone.txt': 1
    }
  }
};

function filePaths(obj, prefix = "", store = []) {
  if (typeof obj !== "object") return [prefix];
  return (prefix && [prefix] || []).concat(...Object.keys(obj).map(k => filePaths(obj[k], prefix + "/" + k, store)))
}

console.log(filePaths(obj))

Comments

1

You're on the right track with recursion. For each call, loop over every property in the current object, make a path for the property and add it to the result array. If the property keys to an object, it's a non-terminal node and is called recursively to add paths for its children.

const pathify = (o, res=[], path=[]) => {
  for (const dir in o) {
    const s = path.join("/");
    res.push(`/${s ? `${s}/${dir}` : dir}`);

    if (typeof o[dir] === "object") {
      pathify(o[dir], res, path.concat(dir));
    }
  }

  return res;
};

const obj = {
  'app': {
    'body': {
      'abs': {
        'muscles.txt': 1
      },
      'foot.js': 1,
      'hand.txt': 1,
      'leg.txt': 1
    },
    'cat.txt': 1,
    'dog.js': 1,
    'writing': {
      'pen.txt': 1,
      'phone.txt': 1
    }
  }
};

console.log(pathify(obj));

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.