Hello everyone,
I’m trying to tackle an algorithm problem and I am running into difficulty.
Here is my code so far:
const classNames = [
'spacing-xs-top-none',
'carousel-mouse-drag-true',
'carousel-xs-display-items-2',
'carousel-md-display-items-1',
'padding-md-left-extra',
'spacing-top-none',
];
const breakpoints = {
xs: 0,
sm: 300,
md: 600,
lg: 900
}
const finalObj = {};
classNames.forEach((className) => {
let classBreakpoint = 'all';
let formattedClassName = className;
Object.keys(breakpoints).forEach((breakpoint) => {
if(className.includes(breakpoint)){
classBreakpoint = breakpoint;
formattedClassName = className.replace(`-${classBreakpoint}`, '');
}
});
let variantName = formattedClassName
.split('-')
.slice(0, 1)
.join();
let variantProperty = formattedClassName
.split('-')
.slice(1, -1)
.join('-');
let variantValue = formattedClassName
.split('-')
.slice(-1)
.join();
// create the Object
const obj = {};
obj[variantName] = {};
obj[variantName][classBreakpoint] = {};
obj[variantName][classBreakpoint][variantProperty] = variantValue;
});
console.log(finalObj);
// desired final object
// {
// spacing: { xs: { top: none }
// all: { top: none }
// }
// carousel: { all: { mouse-drag: true }
// xs: { display-items: 2 }
// md: { display-items: 1 }
// }
// padding: { md: { left: extra } }
// }
The challenge is to loop through the array of classnames and produce an object in the structure of the desired final object provided.
I have gotten to the point where I am creating each classname in the correct format. For example the first loop is returning an object like so:
{ spacing: { xs: { top: 'none' } } }
Which is as desired. My problem is when trying to combine the objects into the final result. I have tried using
Object.assign(finalObj, obj);
at the end of each for loop but it causes key value pairs that already exist in the object to be overwritten.
Output of finalObj
{ spacing: { all: { top: 'none' } },
carousel: { md: { 'display-items': '1' } },
padding: { md: { left: 'extra' } } }
Is there a clever way to merge objects without the key value pairs being overwritten? Or is there a better way of tackling this?
Any help appreciated!
Slight update.
I have managed to get the correct output with the following but I don’t feel the solution is that good
const classNames = [
'spacing-xs-top-none',
'carousel-mouse-drag-true',
'carousel-xs-display-items-2',
'carousel-md-display-items-1',
'padding-md-left-extra',
'spacing-top-none',
];
const breakpoints = {
xs: 0,
sm: 300,
md: 600,
lg: 900
}
const finalObj = {};
classNames.forEach((className) => {
let classBreakpoint = 'all';
let formattedClassName = className;
Object.keys(breakpoints).forEach((breakpoint) => {
if(className.includes(breakpoint)){
classBreakpoint = breakpoint;
formattedClassName = className.replace(`-${classBreakpoint}`, '');
}
});
let variantName = formattedClassName
.split('-')
.slice(0, 1)
.join();
let variantProperty = formattedClassName
.split('-')
.slice(1, -1)
.join('-');
let variantValue = formattedClassName
.split('-')
.slice(-1)
.join();
// create the Object
const obj = {};
if(!finalObj.hasOwnProperty(variantName)){
obj[variantName] = {};
} else {
obj[variantName] = finalObj[variantName];
}
if(!obj[variantName].hasOwnProperty(classBreakpoint)){
obj[variantName][classBreakpoint] = {};
} else {
obj[variantName][classBreakpoint] = finalObj[variantName][classBreakpoint];
}
obj[variantName][classBreakpoint][variantProperty] = variantValue;
Object.assign(finalObj, obj);
});
console.log(finalObj);
// desired final object
// {
// spacing: { xs: { top: none }
// all: { top: none }
// }
// carousel: { all: { mouse-drag: true }
// xs: { display-items: 2 }
// md: { display-items: 1 }
// }
// padding: { md: { left: extra } }
// }
snigo
November 8, 2018, 11:56pm
3
Hey @heenslice , before we get to the object, check this:
let variantProperty = formattedClassName
.split('-')
.slice(1, -1)
.join('-');
What if your class name will include -
? Like carousel-intro
What if your property name will include -
? Like border-box
Hi,
Thanks for responding.
And good catch! I suppose in those cases the object would not be formatted correctly. I was mostly focusing on getting the test cases provided to work but ideally I would be able to handle cases like border-box
Do you have any suggestions on how I can split the string in a more robust way to cover these cases?
ghukahr
November 9, 2018, 12:27am
5
Maybe you can separate them by a character that can’t be used in normal css variables, like ;
.
snigo
November 9, 2018, 1:42am
6
Now, to the object
Normally if you want to combine objects, you do this:
nest = (o, to) => Object.assign(to, o);
Fairly easy, but as you mentioned it will overwrite all nested objects. So you probably need to ‘deepify’ it:
nestDeep = (o, to) => {
// exit condition for recursion
if (typeof to !== 'object') return o;
// let's check every key in object we want to put in
for (let k in o) {
// if we already have this key and what we want to put in is object - recurse
if (to.hasOwnProperty(k) && typeof o[k] === 'object') {
nestDeep(o[k], to[k])
} else {
// else, just put whatever in
to[k] = o[k];
}
}
// return result
return to;
}
const a = { user: { name: 'iiiked', mood: ':(' } };
const b = { user: { age: 35, mood: ':)' , mode: 'dev' } };
console.log(nestDeep(b, a));
Good luck with parsing dashes
Awesome,
Not sure if I really understand what is going on here yet but thanks for the response!
snigo
November 10, 2018, 9:10pm
8
In your code you can do like this:
// Create object
const obj = {};
obj[variantName] = {};
obj[variantName][classBreakpoint] = {};
obj[variantName][classBreakpoint][variantProperty] = variantValue;
nestDeep(obj, finalObj);