I have a array of URLs like this:
const urls = [
'src/components/index.js',
'src/components/style.css',
'readme.txt',
'photos/something/somwhere/why.jpg',
'places/something/home,
];
And I want to have output like this:
{
'src': {
'components': {
'index.js': true,
'style.css': true
}
},
'readme.txt': true,
'photos': {
'something': {
'somewhere': {
'why.jpg'
}
'home': {}
}
}
Where the files in the end should have value true and the empty folders should have an empty object as a value.
So far I tried to do it with nested loops but it always fails. The best option that I had this far was this but it's not complete.
const result = {};
const urls = [
'src/components/index.js',
'src/components/style.css',
'readme.txt',
'photos/something/somwhere/why.jpg',
'places/something/home',
];
const urlArr = [];
urls.forEach(url => {
const items = url.split('/');
urlArr.push(items);
});
for (let i = 0; i < urlArr.length; i++) {
for (let j = 0; j < urlArr[i].length; j++) {
let item = urlArr[i][j];
}
}
console.log(urlArr);
If it's possible to do with outer way it would be great too (say recursion or other stuff).
Checks for '.' to decide if file. Note that this is not a reliable check. This looks like part of a build pipeline, so there should already be a way to determine files from folders.
You don't need a recursive function. The path can be iterated over without branching:
splits the urls by '/' to get the paths to traverse (and gets the base filename)
Traverses into the object and sets the values, creating objects if path doesn't exist yet.
const urls = [
'src/components/index.js',
'src/components/style.css',
'readme.txt',
'photos/something/somwhere/why.jpg',
'places/something/home',
];
const root = {}
for(const url of urls) {
let ptr = root
const stack = url.split('/'), basename = stack.pop()
for(const p of stack) ptr = ptr[p] = ptr[p] || {}
ptr[basename] = /\./.test(basename) || {}
}
console.log(root)
You can do this in a lot of different ways, however this is how I would do it.
H & T stands for Head & Tail and are standard names for when designing recursive function that operate over lists.
const urls = [
'src/components/index.js',
'src/components/style.css',
'readme.txt',
'photos/something/somwhere/why.jpg',
'places/something/home',
];
const recursiveAssign = ([H, ...T], target) => {
if (H.indexOf('.') !== -1) {
target[H] = true;
return;
}
target[H] = target[H] || {};
if (T.length > 0) recursiveAssign(T, target[H]);
}
const createTree = (paths) => {
const acc = {};
for (let path of paths) {
recursiveAssign(path.split('/'), acc);
}
return acc;
}
console.log(createTree(urls));
Or if you prefer a less verbose way of write the same solution.
const urls = [
'src/components/index.js',
'src/components/style.css',
'readme.txt',
'photos/something/somwhere/why.jpg',
'places/something/home',
]
const recursiveAssign = ([H, ...T], target) =>
H.indexOf('.') !== -1
? target[H] = true
: T.length > 0
? recursiveAssign(T, target[H] = target[H] || {})
: target[H] = {}
const createTree = ([H, ...T], acc = {}) => (
recursiveAssign(H.split('/'), acc),
T.length > 0
? createTree(T, acc)
: acc
)
console.log(createTree(urls))
Related
I have an array of Java-style package names and want to sort it in a specific way. The sort order I want is generally alphabetically, but with the additional requirement that lowercase always goes either before or after uppercase, depending on a user supplied flag to the sorting function (which allows also a third option of leaving the original order alone).
Example:
const importStrings = [
"foo.bar.Zonk",
"lorem.ipsum.acme.Rocket",
"foo.bar.BazFoo",
"lorem.ipsum.Blah",
"foo.bar.baz.Gnarf",
"lorem.ipsum.acme.Amboss",
];
The order I want is either uppercase first on any given .:
[
"foo.bar.BazFoo",
"foo.bar.Zonk",
"foo.bar.baz.Gnarf",
"lorem.ipsum.Blah",
"lorem.ipsum.acme.Amboss",
"lorem.ipsum.acme.Rocket",
]
or lowercase first:
[
"foo.bar.baz.Gnarf",
"foo.bar.BazFoo",
"foo.bar.Zonk",
"lorem.ipsum.acme.Amboss",
"lorem.ipsum.acme.Rocket",
"lorem.ipsum.Blah",
]
Effectively, I want the sort order to be A-Za-z/a-zA-Z instead of AaBb..Zz/aAbB..zZ, which seems to be surprisingly difficult to achieve unless I'm missing something really, really obvious. All my previous experiments with various custom Array.sort() functions and localeCompare() options didn't yield the output I need.
My current approach kinda-works, but contains a ton of boilerplate and cruft, and I'm thinking that there has to be a better way of doing this. I currently split the individual strings on ., recursively build a object graph containing each "level" of the package name in an array, and then sort that array. That gives me the ordering I want, which I can then merge back together:
function createImportData(data, parts, sortFunction, reduceFunction) {
const packageName = parts.shift();
let localData = data.find((obj) => obj.value === packageName);
if (!localData) {
localData = { value: packageName, children: [] };
data.push(localData);
}
if (parts.length) {
createImportData(localData.children, parts, sortFunction, reduceFunction);
localData.children = localData.children
.reduce(reduceFunction, [[], []])
.flatMap((array) => array.sort(sortFunction));
}
}
function getSortFunction(options) {
if (!shouldOrganizeImports(options)) {
// leave all
return (obj1, obj2) => 0;
} else {
return (obj1, obj2) => {
obj1.value.localeCompare(obj2.value);
};
}
}
function getReduceFunction(options) {
if (!shouldOrganizeImports(options)) {
// just put it in a single array without changing anything
return (groups, obj) => {
groups[0].push(obj);
return groups;
};
} else {
const upperIndex = shouldOrganizeImportsUppercaseFirst(options) ? 0 : 1;
const lowerIndex = shouldOrganizeImportsUppercaseFirst(options) ? 1 : 0;
const reduce = (upperIndex, lowerIndex) => (groups, obj) => {
obj.value.charAt(0).toUpperCase() === obj.value.charAt(0)
? groups[upperIndex].push(obj)
: groups[lowerIndex].push(obj);
return groups;
};
return reduce(upperIndex, lowerIndex);
}
}
//initial call looks like this:
const importData = [];
const sortFunction = getSortFunction(options);
const reduceFunction = getReduceFunction(options);
for (const importString of importStrings) {
createImportData(
importData,
importString.split("."),
sortFunction,
reduceFunction
);
}
The generated structure looks like this, with each level's children array sorted the way I need:
[
{
value: "foo",
children: [
{
value: "bar",
children: [
{ value: "baz", children: [{ value: "Gnarf", children: [] }] },
{ value: "BazFoo", children: [] },
{ value: "Zonk", children: [] },
],
},
],
},
{value: "lorem", children: [/* etc.etc. */]}
]
How can I improve on my logic, or is this already the way to do it?
That's a fairly idiosyncratic sort, but it's possible to do it a bit more concisely using Intl.Collator along with breaking the package names into their individual parts and custom logic to always put something starting with upper case before/after something starting with lower case regardless of length:
// Tells us whether a string starst with an English uppercase char
// (may need tweaking for non-English)
const startsUppercase = /^[A-Z]/;
function sort(array, upperFirst) {
// Get a collator for the current locale with the appropriate case first flag,
// and grab its `compare` function
const collator = new Intl.Collator(undefined, { caseFirst: upperFirst ? "upper" : "lower"});
const { compare } = collator;
// Get a direction flag based on the upper-first/lower-first flag
const direction = upperFirst ? -1 : 1;
// Sort
array.sort((a, b) => {
// Get the two package names split into their parts
const aparts = a.split(".");
const bparts = b.split(".");
// Assume they're equal...
let result = 0;
// Loop through as long as A) they're still equal, and
// B) we have both `a` and `b` parts
const length = Math.min(a.length, b.length);
for (let i = 0; result === 0 && i < length; ++i) {
const apart = aparts[i];
const bpart = bparts[i];
const aupper = startsUppercase.test(apart);
const bupper = startsUppercase.test(bpart);
if (aupper && !bupper) {
// `a` comes first/last
result = direction;
} else if (!aupper && bupper) {
// `b` comes first/last
result = -direction;
} else {
// Same case, compare remainder
result = compare(apart, bpart);
}
}
// If still no difference, compare on segment length
if (result === 0) {
return aparts.length - bparts.length;
}
return result;
});
return array;
}
Live Example:
const importStrings = [
"foo.bar.Zonk",
"lorem.ipsum.acme.Rocket",
"foo.bar.BazFoo",
"lorem.ipsum.Blah",
"foo.bar.baz.Gnarf",
"lorem.ipsum.acme.Amboss",
];
// Tells us whether a string starst with an English uppercase char
// (may need tweaking for non-English)
const startsUppercase = /^[A-Z]/;
function sort(array, upperFirst) {
// Get a collator for the current locale with the appropriate case first flag,
// and grab its `compare` function
const collator = new Intl.Collator(undefined, { caseFirst: upperFirst ? "upper" : "lower"});
const { compare } = collator;
// Get a direction flag based on the upper-first/lower-first flag
const direction = upperFirst ? -1 : 1;
// Sort
array.sort((a, b) => {
// Get the two package names split into their parts
const aparts = a.split(".");
const bparts = b.split(".");
// Assume they're equal...
let result = 0;
// Loop through as long as A) they're still equal, and
// B) we have both `a` and `b` parts
const length = Math.min(a.length, b.length);
for (let i = 0; result === 0 && i < length; ++i) {
const apart = aparts[i];
const bpart = bparts[i];
const aupper = startsUppercase.test(apart);
const bupper = startsUppercase.test(bpart);
if (aupper && !bupper) {
// `a` comes first/last
result = direction;
} else if (!aupper && bupper) {
// `b` comes first/last
result = -direction;
} else {
// Same case, compare remainder
result = compare(apart, bpart);
}
}
// If still no difference, compare on segment length
if (result === 0) {
return aparts.length - bparts.length;
}
return result;
});
return array;
}
console.log(`Upper first:`);
console.log(sort(importStrings.slice(), true));
console.log(`Lower first:`);
console.log(sort(importStrings.slice(), false));
.as-console-wrapper {
max-height: 100% !important;
}
If the array is large, it might be worth pre-splitting the package names so you do it only once rather than repeatedly (since the same string is often presented to the sort callback in the process of sorting large arrays). It's not a big change, see ***:
// Tells us whether a string starst with an English uppercase char
// (may need tweaking for non-English)
const startsUppercase = /^[A-Z]/;
function sort(array, upperFirst) {
// Get a collator for the current locale with the appropriate case first flag,
// and grab its `compare` function
const collator = new Intl.Collator(undefined, { caseFirst: upperFirst ? "upper" : "lower"});
const { compare } = collator;
// Get a direction flag based on the upper-first/lower-first flag
const direction = upperFirst ? -1 : 1;
// *** Get the pre-split package names
const names = new Map(array.map(name => [name, name.split(".")]));
// Sort
array.sort((a, b) => {
// Get the two package names split into their parts
const aparts = names.get(a); // ***
const bparts = names.get(b); // ***
// Assume they're equal...
let result = 0;
// Loop through as long as A) they're still equal, and
// B) we have both `a` and `b` parts
const length = Math.min(a.length, b.length);
for (let i = 0; result === 0 && i < length; ++i) {
const apart = aparts[i];
const bpart = bparts[i];
const aupper = startsUppercase.test(apart);
const bupper = startsUppercase.test(bpart);
if (aupper && !bupper) {
// `a` comes first/last
result = direction;
} else if (!aupper && bupper) {
// `b` comes first/last
result = -direction;
} else {
// Same case, compare remainder
result = compare(apart, bpart);
}
}
// If still no difference, compare on segment length
if (result === 0) {
return aparts.length - bparts.length;
}
return result;
});
return array;
}
Live Example:
const importStrings = [
"foo.bar.Zonk",
"lorem.ipsum.acme.Rocket",
"foo.bar.BazFoo",
"lorem.ipsum.Blah",
"foo.bar.baz.Gnarf",
"lorem.ipsum.acme.Amboss",
];
// Tells us whether a string starst with an English uppercase char
// (may need tweaking for non-English)
const startsUppercase = /^[A-Z]/;
function sort(array, upperFirst) {
// Get a collator for the current locale with the appropriate case first flag,
// and grab its `compare` function
const collator = new Intl.Collator(undefined, { caseFirst: upperFirst ? "upper" : "lower"});
const { compare } = collator;
// Get a direction flag based on the upper-first/lower-first flag
const direction = upperFirst ? -1 : 1;
// *** Get the pre-split package names
const names = new Map(array.map(name => [name, name.split(".")]));
// Sort
array.sort((a, b) => {
// Get the two package names split into their parts
const aparts = names.get(a); // ***
const bparts = names.get(b); // ***
// Assume they're equal...
let result = 0;
// Loop through as long as A) they're still equal, and
// B) we have both `a` and `b` parts
const length = Math.min(a.length, b.length);
for (let i = 0; result === 0 && i < length; ++i) {
const apart = aparts[i];
const bpart = bparts[i];
const aupper = startsUppercase.test(apart);
const bupper = startsUppercase.test(bpart);
if (aupper && !bupper) {
// `a` comes first/last
result = direction;
} else if (!aupper && bupper) {
// `b` comes first/last
result = -direction;
} else {
// Same case, compare remainder
result = compare(apart, bpart);
}
}
// If still no difference, compare on segment length
if (result === 0) {
return aparts.length - bparts.length;
}
return result;
});
return array;
}
console.log(`Upper first:`);
console.log(sort(importStrings.slice(), true));
console.log(`Lower first:`);
console.log(sort(importStrings.slice(), false));
.as-console-wrapper {
max-height: 100% !important;
}
This is an approach where the character are extended to two characters, depening on their case:
lower, after sorting
---------------------------------------------
f o o . b a r . b a z .G n a r f
f o o . b a r .B a zF o o
f o o . b a r .Z o n k
l o r e m . i p s u m . a c m e .A m b o s s
l o r e m . i p s u m . a c m e .R o c k e t
l o r e m . i p s u m .B l a h
upper, after sorting
---------------------------------------------
f o o . b a r . Ba z Fo o
f o o . b a r . Zo n k
f o o . b a r . b a z . Gn a r f
l o r e m . i p s u m . Bl a h
l o r e m . i p s u m . a c m e . Am b o s s
l o r e m . i p s u m . a c m e . Ro c k e t
The the original data is mapped by the sorted indices.
const
sort = (array, priority) => {
const order = priority === 'lower';
return array
.map((s, index) => {
const o = { index, value: '' };
for (const c of s) o.value += c === c.toLowerCase() === order ? ' ' + c : c + ' ';
return o;
})
.sort((a, b) => a.value.localeCompare(b.value))
.map(({ index }) => array[index]);
},
data = ["foo.bar.Zonk", "lorem.ipsum.acme.Rocket", "foo.bar.BazFoo", "lorem.ipsum.Blah", "foo.bar.baz.Gnarf", "lorem.ipsum.acme.Amboss"],
sorted1 = sort(data, 'lower'),
sorted2 = sort(data, 'upper');
console.log(sorted1);
console.log(sorted2);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Hihi,
My question is simple. I'm trying to implement mergesort but having a limitation with the structure of my project
I have a file called sort.js
const selSort = require('./selectionSort');
const bubSort = require('./bubbleSort');
const inSort = require('./insertionSort');
const merSort = require('./mergeSort');
const sort = (arr) => {
const array = arr;
return {
...selSort(array),
...bubSort(array),
...inSort(array),
...merSort(array),
};
};
As you can see I'm trying to implement multiple sort algorithm and make an object
well, now while I started doing the MergeAlgorithm (a recursive sort algorithm) I faced with the problem of the objects in JavaScript
const merge = (left, right) => {
const result = [];
while (left.length && right.legnth) {
result.push(left[0] < right[0] ? left.shifth() : right.shifth());
}
return [...result, ...left, ...right];
};
const merSort = (array) => ({
mergeSort: () => {
if (array.length === 1) {
return array;
}
const middle = Math.floor(array.length);
const leftArr = array.slice(0, middle);
const rightArr = array.slice(middle);
return merge(this(leftArr).mergeSort(), this(rightArr).mergeSort());
},
});
module.exports = merSort;
I cant call mergeSort() and pass to it the left and right array without calling itself again.
Is there anyway to solve this?
I tried using this but it didn't worked
I think there is no way to achive what I want
Why are you using the spread operator ( ... ) all the time ? Also why are you reassigning the arr argument to a constant?
This should work just fine
const selSort = require('./selectionSort');
const bubSort = require('./bubbleSort');
const inSort = require('./insertionSort');
const merSort = require('./mergeSort');
const sort = (arr) => {
return {
selSort(arr),
bubSort(arr),
inSort(arr),
merSort(arr),
};
};
Also for the sorting code this should work
function mergeSort(unsortedArray) {
if (unsortedArray.length <= 1) {
return unsortedArray;
}
const middle = Math.floor(unsortedArray.length / 2);
const left = unsortedArray.slice(0, middle);
const right = unsortedArray.slice(middle);
return merge(mergeSort(left,), mergeSort(right));
}
function merge(left, right) {
let resultArray = [],
leftIndex = 0,
rightIndex = 0;
while (leftIndex < left.length && rightIndex < right.length) {
if (left[leftIndex] < right[rightIndex]) {
resultArray.push(left[leftIndex]);
leftIndex++;
} else {
resultArray.push(right[rightIndex]);
rightIndex++;
}
}
return resultArray
.concat(left.slice(leftIndex))
.concat(right.slice(rightIndex));
}
module.exports = mergeSort;
I am using node to convert an array to object, I have an array looks like this
[
'items[0].book=Book1',
'items[0].color=Red',
'items[0].bookCode=#1',
'items[1].book=Book2',
'items[1].color=Yellow',
'items[1].bookCode=#2',
'items[2].book=Book3',
'items[2].color=Blue',
'items[2].bookCode=#3',
...
]
I am trying to convert it to be objets in one array
items:[
{
book: "Book1",
color: "Red",
bookCode: "#1"
},
{
book: "Book2",
color: "Yellow",
bookCode: "#2"
},
...
]
I found it is easy to conver it uses a 3rd party lib like setKeypath/set,
const obj = {};
const arr = [items......(like above)]
arr.forEach((val => {
if (val.startsWith('items[')) {
const splitWord = item.split('=');
setKeypath(obj, splitWord[0], splitWord[1]);
}
});
I am seeking a way if it can be done the same output with es6, so I don't really need a library. Thanks
const items = [
"items[0].book=Book1",
"items[0].color=Red",
"items[0].bookCode=#1",
"items[1].book=Book2",
"items[1].color=Yellow",
"items[1].bookCode=#2",
"items[2].book=Book3",
"items[2].color=Blue",
"items[2].bookCode=#3"
];
let res = [];
let currId = "";
let currItem = null;
for (let i = 0; i < items.length; i++) {
let parts = items[i].split(".");
if (currId!==parts[0] && currItem) { //new item
res.push(currItem)
currId = parts[0];
}
if (!currItem)
currItem = {};
let keyValue = parts[1].split("=");
currItem[keyValue[0]] = keyValue[1]
}
console.log({items: res})
You may first find all values by regex, and insert the attribute to each corresponding element one by one. This approach works for whatever ordering the array is, and whatever attributes there are, as long as each element follow the same pattern.
let items = [
"items[1].bookCode=#2",
"items[0].book=Book1",
"items[0].bookCode=#1",
"items[1].book=Book2",
"items[2].bookCode=#3",
"items[1].color=Yellow",
"items[2].book=Book3",
"items[2].color=Blue",
"items[0].color=Red",
"items[4].test=test!"
];
let indexPattern = /\[(\d*)\]/;
let attrPattern = /\.(.*)=/;
let valuePattern = /=(.*)/;
let obj = Object.values(
items.reduce((obj, element) => {
let index = element.match(indexPattern)[1];
let attr = element.match(attrPattern)[1];
let value = element.match(valuePattern)[1];
if (!obj.hasOwnProperty(index)) obj[index] = {};
obj[index][attr] = value;
return obj;
}, {})
);
console.log(obj);
[
'items[0].book=Book1',
'items[0].color=Red',
'items[0].bookCode=#1',
'items[1].book=Book2',
'items[1].color=Yellow',
'items[1].bookCode=#2',
'items[2].book=Book3',
'items[2].color=Blue',
'items[2].bookCode=#3',
].reduce((acc, str) => {
const index = Number(str.slice(str.indexOf('[') + 1, str.indexOf(']')));
if (!acc[index]) {
acc[index] = {};
}
const entry = [str.slice(str.indexOf('.') + 1, str.indexOf('=')), str.slice(str.indexOf('=') + 1)];
acc[index][entry[0]] = entry[1];
return acc;
}, []);
Here I pick apart the string you're given based on the consistent format, grab the index, key, and value, and then just use Array#reduce to do the work of putting the array together.
Documentation:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce
I think a smattering of regex would do the trick:
const ar = [
'items[0].book=Book1',
'items[0].color=Red',
'items[0].bookCode=#1',
'items[1].book=Book2',
'items[1].color=Yellow',
'items[1].bookCode=#2',
'items[2].book=Book3',
'items[2].color=Blue',
'items[2].bookCode=#3'
]
const result = [];
ar.forEach(item => {
const index = parseInt(item.match(/\[([0-9]+)\]/)[1]);
const params = item.split(".")[1].split("=");
if(!result[index])
result[index] = {}
result[index][params[0]] = params[1];
})
console.log(result)
Note that item.match(/\[([0-9]+)\]/) matches the number inside your brackets. match returns an array where 1 is the index of the actual value between the brackets.
Let's say I have an array of names such as :
let members = ["John", "Marie", "Ivy", "Daniel"];
Each person has to deliver a unique item to another. Here is an example of 1 combination set :
[
{"John":"Marie"},
{"Marie":"Ivy"},
{"Ivy":"Daniel"},
{"Daniel":"John"},
]
The reciever can only be named once. I'd like to retrieve an array of all combinations possible. What would be the easiest way to get such an array ?
EDIT : Alot of downvotes. Justified I'm afraid. Here is what I worked on, seems... verbose :
//gets all permutations combination of the same array
const perm = members => members.length ? members.reduce((r, v, i) => [ ...r, ...perm([ ...members.slice(0, i), ...members.slice(i + 1) ]).map(x => [ v, ...x ])], []) : [[]]
let permutations = perm(members);
permutations.map(set => {
let valid = true;
let combination = [];
set.map((name, i) => {
let match = {};
if (name === members[i]) {
valid = false;
return
}
match[members[i]] = name;
combination.push(match);
})
if (valid) possibilities.push(combination);
})
try this
let rslt = []
let members = ["John", "Marie", "Ivy", "Daniel"];
members.forEach((member, i) => {
let nextIndex = i + 1;
// if it's the last member
// then pass it to the first one
if (nextIndex === members.length) {
nextIndex = 0;
}
let obj = new Object();
obj[member] = members[nextIndex];
rslt.push(obj);
})
console.log(rslt);
I like to create a object that looks like this for the following URL:
faq/jamie/hutber/faq.json
faq/jamie/hutber/faq_sales.json
sales/people/faq_refunds.json
{
faq: {
jamie: {
hutber:[
"faq.json",
"faq_sales.json"
]
}
},
sales: {
people: [
faq_refunds.json
]
}
}
I feel confident to be able to build we'll need some kind of recursion... which I am lacking in.
const data = {}
const list = 'faq/jamie/hutber/faq.json'.split('/').reverse();
list.forEach((cur, index) => {
if(cur.includes('.json')){
data[cur];
} else if(poo[cur]) {
data[cur] = {}
}else{
data[cur] = {}
}
});
var a = ["faq/jamie/hutber/faq.json",
"faq/jamie/hutber/faq_sales.json",
"sales/people/faq_refunds.json"]; //your URLs
var jsonObj = {}; //this json object will store your result
function urlToJson(array, index, jsonObj){ //function that implements your logic
if(index == array.length - 2){
jsonObj[ array[index] ] = jsonObj[ array[index] ] || [];
jsonObj[ array[index] ].push(array[index + 1]);
return;
}
jsonObj[ array[index] ] = jsonObj[ array[index] ] || {};
urlToJson(array, index + 1, jsonObj[ array[index] ]);
}
for(var key in a){
var array = a[key].split("/");
urlToJson(array, 0, jsonObj);
}
console.log(jsonObj);
You can do this in a loop. Note that you won't support folders that contain both folders and files in your current format.
Here's an example that loops over all paths and adds object to the tree. It's a bit ugly, but it should help you write your own function.
const paths = [
"faq/jamie/hutber/faq.json",
"faq/jamie/hutber/faq_sales.json",
"sales/people/faq_refunds.json"
];
const makeTree = (paths, tree = {}) =>
paths.reduce(
(tree, path) => {
const parts = path.split("/");
const folders = parts.slice(0, -2);
const container = parts[parts.length - 2];
const file = parts[parts.length - 1];
let loc = tree;
folders.forEach(f => {
loc[f] = loc[f] || {};
loc = loc[f];
});
loc[container] = loc[container] || [];
loc[container].push(file);
return tree;
},
tree
);
console.log(makeTree(paths));