Skip to content

Instantly share code, notes, and snippets.

@JamieMason
Last active June 14, 2021 05:20
Show Gist options
  • Star 12 You must be signed in to star a gist
  • Fork 4 You must be signed in to fork a gist
  • Save JamieMason/4be6028de0608d5854c0 to your computer and use it in GitHub Desktop.
Save JamieMason/4be6028de0608d5854c0 to your computer and use it in GitHub Desktop.
Perform a deeply recursive reduce on a JSON-encodable JavaScript Object hierarchy.
/**
* Perform a deeply recursive reduce on a set of JSON, or a JSON-encodable Object hierarchy.
*
* @param {Array|Object} collection
* @param {Function} fn
* @param {*} memo
* @return {*}
*/
function deepReduce(collection, fn, memo) {
/**
* @inner
* @param {*} value
* @param {String[]} path
* @return {*}
*/
function iterator(value, path) {
var type = Object.prototype.toString.call(value);
memo = fn(memo, value, path);
if (type === '[object Array]') {
for (var i = 0, len = value.length; i < len; i++) {
iterator(value[i], path.concat(i));
}
} else if (type === '[object Object]') {
for (var key in value) {
iterator(value[key], path.concat(key));
}
}
return memo;
}
return iterator(collection, []);
}
/*
* Equivalent version in TypeScript
*/
import { each, isArray, isObject } from 'lodash';
export function deepReduce<In, Out>(
reducer: (accumulator: Out, value: any, path: Array<string | number>) => Out,
collection: In,
accumulator: Out,
): Out {
const iterator = <T>(value: T, paths: Array<string | number>) => {
accumulator = reducer(accumulator, value, paths);
if (isArray(value) || isObject(value)) {
each(value, (innerValue, innerKey) =>
iterator<typeof innerValue>(innerValue, paths.concat(innerKey)),
);
}
};
iterator<In>(collection, []);
return accumulator;
}
@JamieMason
Copy link
Author

JavaScript Deep Reduce

Performs a deeply recursive reduce on a JSON-encodable JavaScript Object hierarchy.

Example

The following iterator flattens a deeply nested JavaScript object hierarchy into a single object.

deepReduce(data, function(memo, value, path) {
  memo[path.join('.')] = value;
  return memo;
}, {});

Input

When data is;

var data = [{
  "id": 0,
  "isActive": false,
  "balance": "$1,994.61",
  "age": 20,
  "eyeColor": "brown",
  "name": "Lesley Ford",
  "company": "NEUROCELL",
  "email": "lesleyford@neurocell.com",
  "phone": "+1 (888) 558-3380",
  "tags": [
    "amet",
    "nostrud",
    "ea",
    "minim"
  ],
  "friends": [{
    "id": 0,
    "name": "Key Silva"
  }, {
    "id": 1,
    "name": "Weiss Combs"
  }]
}, {
  "id": 1,
  "isActive": false,
  "balance": "$2,051.93",
  "age": 24,
  "eyeColor": "blue",
  "name": "Reid Carson",
  "company": "JASPER",
  "email": "reidcarson@jasper.com",
  "phone": "+1 (852) 474-2176",
  "tags": [
    "deserunt",
    "laboris",
    "laborum",
    "Lorem"
  ],
  "friends": [{
    "id": 0,
    "name": "Lee Ingram"
  }, {
    "id": 1,
    "name": "Martha Mcintyre"
  }]
}];

Output

Our example produces the following output;

{
  "0": {
    "id": 0,
    "isActive": false,
    "balance": "$1,994.61",
    "age": 20,
    "eyeColor": "brown",
    "name": "Lesley Ford",
    "company": "NEUROCELL",
    "email": "lesleyford@neurocell.com",
    "phone": "+1 (888) 558-3380",
    "tags": [
      "amet",
      "nostrud",
      "ea",
      "minim"
    ],
    "friends": [{
      "id": 0,
      "name": "Key Silva"
    }, {
      "id": 1,
      "name": "Weiss Combs"
    }]
  },
  "1": {
    "id": 1,
    "isActive": false,
    "balance": "$2,051.93",
    "age": 24,
    "eyeColor": "blue",
    "name": "Reid Carson",
    "company": "JASPER",
    "email": "reidcarson@jasper.com",
    "phone": "+1 (852) 474-2176",
    "tags": [
      "deserunt",
      "laboris",
      "laborum",
      "Lorem"
    ],
    "friends": [{
      "id": 0,
      "name": "Lee Ingram"
    }, {
      "id": 1,
      "name": "Martha Mcintyre"
    }]
  },
  "": [{
    "id": 0,
    "isActive": false,
    "balance": "$1,994.61",
    "age": 20,
    "eyeColor": "brown",
    "name": "Lesley Ford",
    "company": "NEUROCELL",
    "email": "lesleyford@neurocell.com",
    "phone": "+1 (888) 558-3380",
    "tags": [
      "amet",
      "nostrud",
      "ea",
      "minim"
    ],
    "friends": [{
      "id": 0,
      "name": "Key Silva"
    }, {
      "id": 1,
      "name": "Weiss Combs"
    }]
  }, {
    "id": 1,
    "isActive": false,
    "balance": "$2,051.93",
    "age": 24,
    "eyeColor": "blue",
    "name": "Reid Carson",
    "company": "JASPER",
    "email": "reidcarson@jasper.com",
    "phone": "+1 (852) 474-2176",
    "tags": [
      "deserunt",
      "laboris",
      "laborum",
      "Lorem"
    ],
    "friends": [{
      "id": 0,
      "name": "Lee Ingram"
    }, {
      "id": 1,
      "name": "Martha Mcintyre"
    }]
  }],
  "0.id": 0,
  "0.isActive": false,
  "0.balance": "$1,994.61",
  "0.age": 20,
  "0.eyeColor": "brown",
  "0.name": "Lesley Ford",
  "0.company": "NEUROCELL",
  "0.email": "lesleyford@neurocell.com",
  "0.phone": "+1 (888) 558-3380",
  "0.tags": [
    "amet",
    "nostrud",
    "ea",
    "minim"
  ],
  "0.tags.0": "amet",
  "0.tags.1": "nostrud",
  "0.tags.2": "ea",
  "0.tags.3": "minim",
  "0.friends": [{
    "id": 0,
    "name": "Key Silva"
  }, {
    "id": 1,
    "name": "Weiss Combs"
  }],
  "0.friends.0": {
    "id": 0,
    "name": "Key Silva"
  },
  "0.friends.0.id": 0,
  "0.friends.0.name": "Key Silva",
  "0.friends.1": {
    "id": 1,
    "name": "Weiss Combs"
  },
  "0.friends.1.id": 1,
  "0.friends.1.name": "Weiss Combs",
  "1.id": 1,
  "1.isActive": false,
  "1.balance": "$2,051.93",
  "1.age": 24,
  "1.eyeColor": "blue",
  "1.name": "Reid Carson",
  "1.company": "JASPER",
  "1.email": "reidcarson@jasper.com",
  "1.phone": "+1 (852) 474-2176",
  "1.tags": [
    "deserunt",
    "laboris",
    "laborum",
    "Lorem"
  ],
  "1.tags.0": "deserunt",
  "1.tags.1": "laboris",
  "1.tags.2": "laborum",
  "1.tags.3": "Lorem",
  "1.friends": [{
    "id": 0,
    "name": "Lee Ingram"
  }, {
    "id": 1,
    "name": "Martha Mcintyre"
  }],
  "1.friends.0": {
    "id": 0,
    "name": "Lee Ingram"
  },
  "1.friends.0.id": 0,
  "1.friends.0.name": "Lee Ingram",
  "1.friends.1": {
    "id": 1,
    "name": "Martha Mcintyre"
  },
  "1.friends.1.id": 1,
  "1.friends.1.name": "Martha Mcintyre"
}

@anicarrr
Copy link

Thanks mate. I was looking for something like this, saved my day!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment