diff --git a/README.md b/README.md index 0d4a67a91..0a640e34a 100644 --- a/README.md +++ b/README.md @@ -319,6 +319,7 @@ average(1, 2, 3); * [`equals`](#equals-) * [`findKey`](#findkey) * [`findLastKey`](#findlastkey) +* [`flattenObject`](#flattenobject) * [`forOwn`](#forown) * [`forOwnRight`](#forownright) * [`functions`](#functions) @@ -341,6 +342,7 @@ average(1, 2, 3); * [`size`](#size) * [`transform`](#transform) * [`truthCheckCollection`](#truthcheckcollection) +* [`unflattenObject`](#unflattenobject-) @@ -5541,6 +5543,38 @@ findLastKey(
[⬆ Back to top](#table-of-contents) +### flattenObject + +Flatten an object with the paths for keys. + +Use recursion. +Use `Object.keys(obj)` combined with `Array.reduce()` to convert every leaf node to a flattened path node. +If the value of a key is an object, the function calls itself with the appropriate `prefix` to create the path using `Object.assign()`. +Otherwise, it adds the appropriate prefixed key-value pair to the accumulator object. +You should always omit the second argument, `prefix`, unless you want every key to have a prefix. + +```js +const flattenObject = (obj, prefix = '') => + Object.keys(obj).reduce((acc, k) => { + const pre = prefix.length ? prefix + '.' : ''; + if (typeof obj[k] === 'object') Object.assign(acc, flattenObject(obj[k], pre + k)); + else acc[pre + k] = obj[k]; + return acc; + }, {}); +``` + +
+Examples + +```js +flattenObject({ a: { b: { c: 1 } }, d: 1 }); // { 'a.b.c': 1, d: 1 } +``` + +
+ +
[⬆ Back to top](#table-of-contents) + + ### forOwn Iterates over all own properties of an object, running a callback for each one. @@ -6153,6 +6187,45 @@ truthCheckCollection([{ user: 'Tinky-Winky', sex: 'male' }, { user: 'Dipsy', sex
[⬆ Back to top](#table-of-contents) + +### unflattenObject ![advanced](/advanced.svg) + +Unlatten an object with the paths for keys. + +Use `Object.keys(obj)` combined with `Array.reduce()` to convert flattened path node to a leaf node. +If the value of a key contains a dot delimiter (`.`), use `Array.split('.')`, string transformations and `JSON.parse()` to create an object, then `Object.assign()` to create the leaf node. +Otherwise, add the appropriate key-value pair to the accumulator object. + +```js +const unflattenObject = obj => + Object.keys(obj).reduce((acc, k) => { + if (k.indexOf('.') !== -1) { + const keys = k.split('.'); + Object.assign( + acc, + JSON.parse( + '{' + + keys.map((v, i) => (i !== keys.length - 1 ? `"${v}":{` : `"${v}":`)).join('') + + obj[k] + + '}'.repeat(keys.length) + ) + ); + } else acc[k] = obj[k]; + return acc; + }, {}); +``` + +
+Examples + +```js +unflattenObject({ 'a.b.c': 1, d: 1 }); // { a: { b: { c: 1 } }, d: 1 } +``` + +
+ +
[⬆ Back to top](#table-of-contents) + --- ## 📜 String diff --git a/docs/index.html b/docs/index.html index 12791811b..54ff3a766 100644 --- a/docs/index.html +++ b/docs/index.html @@ -50,7 +50,7 @@ scrollToTop(); } }, false); - }

logo 30 seconds of code Curated collection of useful JavaScript snippets that you can understand in 30 seconds or less.

 

Adapter

ary

Creates a function that accepts up to n arguments, ignoring any additional arguments.

Call the provided function, fn, with up to n arguments, using Array.slice(0,n) and the spread operator (...).

const ary = (fn, n) => (...args) => fn(...args.slice(0, n));
+      }

logo 30 seconds of code Curated collection of useful JavaScript snippets that you can understand in 30 seconds or less.

 

Adapter

ary

Creates a function that accepts up to n arguments, ignoring any additional arguments.

Call the provided function, fn, with up to n arguments, using Array.slice(0,n) and the spread operator (...).

const ary = (fn, n) => (...args) => fn(...args.slice(0, n));
 
const firstTwoMax = ary(Math.max, 2);
 [[2, 6, 'a'], [8, 4, 6], [10]].map(x => firstTwoMax(...x)); // [6, 8, 10]
 

call

Given a key and a set of arguments, call them when given a context. Primarily useful in composition.

Use a closure to call a stored key with stored arguments.

const call = (key, ...args) => context => context[key](...args);
@@ -1286,6 +1286,14 @@ console.log<
   },
   o => o['active']
 ); // 'pebbles'
+

flattenObject

Flatten an object with the paths for keys.

Use recursion. Use Object.keys(obj) combined with Array.reduce() to convert every leaf node to a flattened path node. If the value of a key is an object, the function calls itself with the appropriate prefix to create the path using Object.assign(). Otherwise, it adds the appropriate prefixed key-value pair to the accumulator object. You should always omit the second argument, prefix, unless you want every key to have a prefix.

const flattenObject = (obj, prefix = '') =>
+  Object.keys(obj).reduce((acc, k) => {
+    const pre = prefix.length ? prefix + '.' : '';
+    if (typeof obj[k] === 'object') Object.assign(acc, flattenObject(obj[k], pre + k));
+    else acc[pre + k] = obj[k];
+    return acc;
+  }, {});
+
flattenObject({ a: { b: { c: 1 } }, d: 1 }); // { 'a.b.c': 1, d: 1 }
 

forOwn

Iterates over all own properties of an object, running a callback for each one.

Use Object.keys(obj) to get all the properties of the object, Array.forEach() to run the provided function for each key-value pair. The callback receives three arguments - the value, the key and the object.

const forOwn = (obj, fn) => Object.keys(obj).forEach(key => fn(obj[key], key, obj));
 
forOwn({ foo: 'bar', a: 1 }, v => console.log(v)); // 'bar', 1
 

forOwnRight

Iterates over all own properties of an object in reverse, running a callback for each one.

Use Object.keys(obj) to get all the properties of the object, Array.reverse() to reverse their order and Array.forEach() to run the provided function for each key-value pair. The callback receives three arguments - the value, the key and the object.

const forOwnRight = (obj, fn) =>
@@ -1441,6 +1449,23 @@ Foo.prototype// { '1': ['a', 'c'], '2': ['b'] }
 

truthCheckCollection

Checks if the predicate (second argument) is truthy on all elements of a collection (first argument).

Use Array.every() to check if each passed object has the specified property and if it returns a truthy value.

const truthCheckCollection = (collection, pre) => collection.every(obj => obj[pre]);
 
truthCheckCollection([{ user: 'Tinky-Winky', sex: 'male' }, { user: 'Dipsy', sex: 'male' }], 'sex'); // true
+

unflattenObjectadvanced

Unlatten an object with the paths for keys.

Use Object.keys(obj) combined with Array.reduce() to convert flattened path node to a leaf node. If the value of a key contains a dot delimiter (.), use Array.split('.'), string transformations and JSON.parse() to create an object, then Object.assign() to create the leaf node. Otherwise, add the appropriate key-value pair to the accumulator object.

const unflattenObject = obj =>
+  Object.keys(obj).reduce((acc, k) => {
+    if (k.indexOf('.') !== -1) {
+      const keys = k.split('.');
+      Object.assign(
+        acc,
+        JSON.parse(
+          '{' +
+            keys.map((v, i) => (i !== keys.length - 1 ? `"${v}":{` : `"${v}":`)).join('') +
+            obj[k] +
+            '}'.repeat(keys.length)
+        )
+      );
+    } else acc[k] = obj[k];
+    return acc;
+  }, {});
+
unflattenObject({ 'a.b.c': 1, d: 1 }); // { a: { b: { c: 1 } }, d: 1 }
 

String

anagrams

⚠️ WARNING: This function's execution time increases exponentially with each character. Anything more than 8 to 10 characters will cause your browser to hang as it tries to solve all the different combinations.

Generates all anagrams of a string (contains duplicates).

Use recursion. For each letter in the given string, create all the partial anagrams for the rest of its letters. Use Array.map() to combine the letter with each partial anagram, then Array.reduce() to combine all anagrams in one array. Base cases are for string length equal to 2 or 1.

const anagrams = str => {
   if (str.length <= 2) return str.length === 2 ? [str, str[1] + str[0]] : [str];
   return str
diff --git a/snippets/flattenObject.md b/snippets/flattenObject.md
index f0fd81f3e..7942f5770 100644
--- a/snippets/flattenObject.md
+++ b/snippets/flattenObject.md
@@ -11,12 +11,8 @@ You should always omit the second argument, `prefix`, unless you want every key
 ```js
 const flattenObject = (obj, prefix = '') =>
   Object.keys(obj).reduce((acc, k) => {
-    const pre = prefix.length ? (prefix + '.') : '';
-    if (typeof obj[k] === 'object')
-      Object.assign(
-        acc,
-        flattenObject(obj[k], pre + k)
-      );
+    const pre = prefix.length ? prefix + '.' : '';
+    if (typeof obj[k] === 'object') Object.assign(acc, flattenObject(obj[k], pre + k));
     else acc[pre + k] = obj[k];
     return acc;
   }, {});
diff --git a/snippets/unflattenObject.md b/snippets/unflattenObject.md
index 570d92215..b4f78bd96 100644
--- a/snippets/unflattenObject.md
+++ b/snippets/unflattenObject.md
@@ -15,9 +15,7 @@ const unflattenObject = obj =>
         acc,
         JSON.parse(
           '{' +
-            keys
-              .map((v, i) => (i !== keys.length - 1 ? `"${v}":{` : `"${v}":`))
-              .join('') +
+            keys.map((v, i) => (i !== keys.length - 1 ? `"${v}":{` : `"${v}":`)).join('') +
             obj[k] +
             '}'.repeat(keys.length)
         )