admin管理员组

文章数量:1134587

I have written this small function to get all keys and values of an object and store them into an array. The object might contain arrays as values...

Object { 0: [1,2,3,4] } to [0,1,2,3,4] converting all elements to integers

I wonder whether there is a faster/cleaner way to do so:

function flattenObject(obj) {
    // Returns array with all keys and values of an object
    var array = [];
    $.each(obj, function (key, value) {
        array.push(key);
        if ($.isArray(value)) {
            $.each(value, function (index, element) {
                array.push(element);
            });
        }
        else {
            array.push(value);
        }
    });

    return array
}

I have written this small function to get all keys and values of an object and store them into an array. The object might contain arrays as values...

Object { 0: [1,2,3,4] } to [0,1,2,3,4] converting all elements to integers

I wonder whether there is a faster/cleaner way to do so:

function flattenObject(obj) {
    // Returns array with all keys and values of an object
    var array = [];
    $.each(obj, function (key, value) {
        array.push(key);
        if ($.isArray(value)) {
            $.each(value, function (index, element) {
                array.push(element);
            });
        }
        else {
            array.push(value);
        }
    });

    return array
}
Share Improve this question edited Oct 17, 2018 at 10:36 Suraj Rao 29.6k11 gold badges95 silver badges104 bronze badges asked May 23, 2017 at 11:58 ddomingoddomingo 1,0231 gold badge12 silver badges14 bronze badges 7
  • 2 please add some data and the wanted output. – Nina Scholz Commented May 23, 2017 at 12:05
  • There really isn't a 'good' way to do this (to arbitrary levels of nesting) in JS. The obvious solution is recursive which means you're potentially dealing with blowing the stack. If you're certain its only one level deep then your code is fine. – Jared Smith Commented May 23, 2017 at 12:12
  • Asking for code improvement is a better fit for codereview.stackexchange.com What don't you like about your code? A question that asks for "best way" is not a good fit for SO because there are many different correct answers. – Ruan Mendes Commented May 23, 2017 at 12:22
  • @JaredSmith Well, the OP doesn't seem to want to do this to arbitrary levels of nesting. In any case, you're not going to blow the stack unless you have objects nested thousands or tens of thousands deep. – user663031 Commented May 23, 2017 at 12:22
  • 2 The operation of flattening an object like this triggers my smell detector. – Anders Lindén Commented May 23, 2017 at 12:34
 |  Show 2 more comments

25 Answers 25

Reset to default 110

I wanted to flatten my deep object to one level depth. None of the above solutions worked for me.

My input:

{
    "user": {
        "key_value_map": {
            "CreatedDate": "123424",
            "Department": {
                "Name": "XYZ"
            }
        }
    }
}

Expected output:

{
    "user.key_value_map.CreatedDate": "123424",
    "user.key_value_map.Department.Name": "XYZ"
}

Code that worked for me:

function flattenObject(ob) {
    var toReturn = {};

    for (var i in ob) {
        if (!ob.hasOwnProperty(i)) continue;

        if ((typeof ob[i]) == 'object' && ob[i] !== null) {
            var flatObject = flattenObject(ob[i]);
            for (var x in flatObject) {
                if (!flatObject.hasOwnProperty(x)) continue;

                toReturn[i + '.' + x] = flatObject[x];
            }
        } else {
            toReturn[i] = ob[i];
        }
    }
    return toReturn;
}

Flattening Object can be done using recursion as below :

Sample Input

const obj = {
    name: "test",
    address: {
        personal: "abc",
        office: {
            building: 'random',
            street: 'some street'
        }
    }
}

Expected Output

{
    name : "test",
    address_personal: "abc"
    address_office_building: "random"
    address_office_street: "some street"
}


My Solution

  function flattenObj(obj, parent, res = {}){
    for(let key in obj){
        let propName = parent ? parent + '_' + key : key;
        if(typeof obj[key] == 'object'){
            flattenObj(obj[key], propName, res);
        } else {
            res[propName] = obj[key];
        }
    }
    return res;
}

Hope it helps

You could just concat all keys and values. (It does not solve the type casting to number for keys.)

var object =  { 0: [1, 2, 3, 4] },
    result = Object.keys(object).reduce(function (r, k) {
        return r.concat(k, object[k]);
    }, []);
    
console.log(result);

This answer is an improvement of @Muthukrishnan 's answer

If you want to flatten an object deeply outputting the values into a one level deep object keyed with the path of the value in the previous object

(eg: { foo: { bar: 'baz'} } => { 'foo.bar': 'baz' })

Here is how you can effectively do it:

/**
 * @param ob Object                 The object to flatten
 * @param prefix String (Optional)  The prefix to add before each key, also used for recursion
 **/
function flattenObject(ob, prefix = false, result = null) {
  result = result || {};

  // Preserve empty objects and arrays, they are lost otherwise
  if (prefix && typeof ob === 'object' && ob !== null && Object.keys(ob).length === 0) {
    result[prefix] = Array.isArray(ob) ? [] : {};
    return result;
  }

  prefix = prefix ? prefix + '.' : '';

  for (const i in ob) {
    if (Object.prototype.hasOwnProperty.call(ob, i)) {
      // Only recurse on true objects and arrays, ignore custom classes like dates
      if (typeof ob[i] === 'object' && (Array.isArray(ob[i]) || Object.prototype.toString.call(ob[i]) === '[object Object]') && ob[i] !== null) {
        // Recursion on deeper objects
        flattenObject(ob[i], prefix + i, result);
      } else {
        result[prefix + i] = ob[i];
      }
    }
  }
  return result;
}

/**
 * Bonus function to unflatten an object
 *
 * @param ob Object     The object to unflatten
 */
function unflattenObject(ob) {
  const result = {};
  for (const i in ob) {
    if (Object.prototype.hasOwnProperty.call(ob, i)) {
      const keys = i.match(/(?:^\.+)?(?:\.{2,}|[^.])+(?:\.+$)?/g); // Just a complicated regex to only match a single dot in the middle of the string
      keys.reduce((r, e, j) => {
        return r[e] || (r[e] = isNaN(Number(keys[j + 1])) ? (keys.length - 1 === j ? ob[i] : {}) : []);
      }, result);
    }
  }
  return result;
}


// TESTS
const obj = {
  value: {
    foo: {
      bar: 'yes',
      so: {
        freakin: {
          nested: 'Wow',
          date: new Date(),
        }
      }
    },
  },
  // Some edge cases to test
  test: [true, false, [null, undefined, 1]],
  not_lost: [], // Empty arrays should be preserved
  not_lost2: {}, // Empty objects should be preserved
  // Be careful with object having dots in the keys
  'I.like.dots..in.object.keys...': "... Please don't override me",
  I: {
    like: {
      'dots..in': {
        object: {
          'keys...': "You've been overwritten"
        }
      }
    }
  }
};
console.log(flattenObject(['I', {'am': 'an array'}]));
let flat = flattenObject(obj);
console.log(flat, unflattenObject(flat));

There is an obvious problem that you could encounter with flattening this way if your object contains keys with dots, this is documented in the fiddle

I needed something really simple and here is a one-liner I came up with:

function flatten(obj){
  return Object.values(obj).flat()
}

Obviously, this is subject to your browser/JS env supporting this syntax (see here). Below is a working example.

const flatten=(obj)=>Object.values(obj).flat()

const x={x:[1,2,3],y:[4,5,6,7]}

console.log(flatten(x))

If you're feeling really lazy then you can make use of the popular NPM library flat.

Example (from their docs)

var flatten = require('flat')

flatten({
    key1: {
        keyA: 'valueI'
    },
    key2: {
        keyB: 'valueII'
    },
    key3: { a: { b: { c: 2 } } }
})

// {
//   'key1.keyA': 'valueI',
//   'key2.keyB': 'valueII',
//   'key3.a.b.c': 2
// }

A more modern JavaScript and TypeScript implementation of a simple object to flat property map converter. It's using Object.entries to do a proper for of loop only on owned properties.

Exmaple Input:

const address = {
  name: 'Address 1',
  address: {
    street: {name: 'Test Street', no: 123}
  }
};

Output:

{
    'address.street.name': 'Test Street'
    'address.street.no': 123
    'name': 'Address 1'
}

JavaScript:

export function toFlatPropertyMap(obj, keySeparator = '.') {
  const flattenRecursive = (obj, parentProperty, propertyMap = {}) => {
    for(const [key, value] of Object.entries(obj)){
      const property = parentProperty ? `${parentProperty}${keySeparator}${key}` : key;
      if(value && typeof value === 'object'){
        flattenRecursive(value, property, propertyMap);
      } else {
        propertyMap[property] = value;
      }
    }
    return propertyMap;
  };
  return flattenRecursive(obj);
}

TypeScript:

export function toFlatPropertyMap(obj: object, keySeparator = '.') {
  const flattenRecursive = (obj: object, parentProperty?: string, propertyMap: Record<string, unknown> = {}) => {
    for(const [key, value] of Object.entries(obj)){
      const property = parentProperty ? `${parentProperty}${keySeparator}${key}` : key;
      if(value && typeof value === 'object'){
        flattenRecursive(value, property, propertyMap);
      } else {
        propertyMap[property] = value;
      }
    }
    return propertyMap;
  };
  return flattenRecursive(obj);
}

I use this recursive function:

function flattenObject(obj, prefix = '') {
  return 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;
  }, {});
}

Example of use:

const obj = { a: { b: { c: 1 } }, d: 1 };
const output = flattenObject(obj);
console.log(output); //{"a.b.c":1,"d":1}

Generate an array of tuples (two-element arrays) of keys and values (which might themselves be arrays), then deep-flatten it.

function flattenObject(obj) { 
      return flatten(Object.keys(obj).map(k => [toNumber(k), obj[k]]));
}

// Substitute your own favorite flattening algorithm.
const flatten = a => Array.isArray(a) ? [].concat(...a.map(flatten)) : a;

// Convert to number, if you can.
const toNumber = n => isNaN(+n) ? n : +n;

console.log(flattenObject({a: [1, 2], b: 3, 0: [1, 2, 3, 4, 5]}));

You can skip the inner loop if you have to push contents of an array to another array. See if this helps --

function flattenObject(obj) {
// Returns array with all keys and values of an object
var array = [];
$.each(obj, function (key, value) {
    array.push(key);
    if ($.isArray(value)) {
        Array.prototype.push.apply(array, value);
    }
    else {
        array.push(value);
    }
});

return array;
}
var obj = {"key1" : [1,3,3],"key2" : "val", "key3":23};
var output = flattenObject(obj);
console.log(output);

Fiddle Link -- https://jsfiddle.net/0wu5z79a/1/

EDIT : This solution is valid only for your scenario where you know that the nesting is till one level only else you need to have some recursion for deep inner objects.

This solution can handle deeply nested objects

const isObject = o => o && typeof o === 'object' && !(o instanceof Date);

const flattenObject = obj => Object.entries(obj).reduce((acc, [key, val]) => ({
  ...acc, ...(isObject(val) ? flattenObject(val) : { [key]: val })
}), {});

Remember that this function returns an empty object for strings, dates, numbers, etc.

Here is my TS implementation

Input:

const object = {
  topLevel: {
    numeric: 0,
    text: "string",
    bool: true,
    nested: {
      notDefined: undefined,
      nulll: null,
      array: [1, 2, 3]
    },
  },
};

const flat = flatten(object);

Expected result:

[
  "[topLevel][numeric]=0",
  "[topLevel][text]=string",
  "[topLevel][bool]=true",
  "[topLevel][nested][notDefined]=undefined",
  "[topLevel][nested][nulll]=null",
  "[topLevel][nested][array]=1,2,3",
]

Code:

export type InputValue = string | number | boolean | undefined | null;
export type ParsedValue = InputValue | InputValue[] | ParsedObject;
export type ParsedObject = { [key in string]: ParsedValue };

export const flatten = (object: ParsedObject, parent?: string): string[] => {
  let results: string[] = [];
  for (let key in object) {
    const value = object[key];
    const thisKey = parent ? `${parent}[${key}]` : `[${key}]`;

    results = results.concat(
      isObject(value) ? flatten(value, thisKey) : `${thisKey}=${value}`
    );
  }

  return results;
};

const isObject = (obj: ParsedValue): obj is ParsedObject => {
  return !!obj && typeof obj === "object" && !Array.isArray(obj);
};

And a JS snippet:

const flatten = (object, parent) => {
  let results = [];
  for (let key in object) {
    const value = object[key];
    const thisKey = parent ? `${parent}[${key}]` : `[${key}]`;

    results = results.concat(
      isObject(value) ? flatten(value, thisKey) : `${thisKey}=${value}`
    );
  }

  return results;
};

const isObject = (obj) => {
  return !!obj && typeof obj === "object" && !Array.isArray(obj);
};

console.log(
  flatten({
    topLevel: {
      numeric: 0,
      text: "string",
      bool: true,
      nested: { notDefined: undefined, nulll: null, array: [1, 2, 3] },
    },
  })
);

Using Reduce in typescript It will be something like

export const flattenObject = (obj: Record<string, unknown>): Record<string, unknown> =>
  Object.entries(obj).reduce((acc, [key, value]) => {
    if (typeof value === 'object' && value !== null) {
      Object.entries(value).forEach(([iKey, iValue]) => {
        acc[`${key}-${iKey}`] = iValue;
      });
    } else {
      acc[key] = value;
    }
    return acc;
  }, {});

Using ES6 spread syntax:

function flattenObj(data, parent = null){
    // Create an empty object .
    let dataMap = {}
    // Loop over the data object that was given .
    for(const key in data){
        // Set a key name by checking if parent was set by previous recursive calls .
        const keyName = parent ? parent + '.' + key : key;
        // Check the data type.
        if(typeof data[key] === 'object' && !Array.isArray(data[key])) {
            // Using ES6 "Spread Operator" i overwrite the dataMap object with:
            // current dataMap + returned object result of the recurive call .
            dataMap = { ...dataMap, ...flattenObj(data[key], keyName)};
        } else {
            // If data type is anything but an object append the "key: value" .
            dataMap[keyName] = data[key];
        }
    }
    return dataMap;
}

var input = {
  name: 'navneet',
  address: {
    personal: "abc",
    office: {
      building: 'random',
      street: 'some street',
      demo: {
        x: 1
      }
    }
  }
};

var output = {};

function flatten(input, parent = '') {

  for (var key in input) {
    var value = input[key];
    if (typeof value === 'object') {
      flatten(value, parent + key + '.');
    } else {
      if (parent) {
        output[parent + key] = value;
      } else {
        output[key] = value;
      }
    }
  }
  return output;
}

var flattened = flatten(input)
console.log(flattened)

The function below will flatten an object to the specified depth. This function uses a loop rather than recursion. You can choose how child property keys are named, the default is 'parent.child'. The result is an array of [key, value] arrays, like Object.entries(). It requires lodash for isPlainObject and partition(), though you could write your own isPlainObject, partition functions if you wanted to remove the dependency.

/**
 * Returns an array containing the properties of the given Object in the same format
 * as Object.entries(). Goes through child objects to the specified depth, 
 * flattening the properties and prefixing child keys with a parent key names.
 * @param {Object} object to retrieve property values for
 * @param {Number} maxDepth the maximum number of times to look at properties of
 * properties of the given object.
 * Set to 1 to only retrieve the property values of the given object, 2 to get
 * properties and sub-properties etc.
 * @param {Function} keyPrefixer a function that takes a parent object name, and
 * a child object name and returns a string representing the combined name.
 * @returns {Array} containing the properties and child properties of the given object.
 * Each property is returned as an array [key, value]. 
 * Returns an empty array if object is null, undefined, not-an-object, or empty.
 */
const flattenEntries = (
  object,
  maxDepth = 2,
  keyPrefixer = (parentKey, childKey) => `${parentKey}.${childKey}`) => {

  if (!object || !_.isPlainObject(object)) {
    return [];
  }

  // make maxDepth >= 1
  maxDepth = Math.max(1, Math.abs(maxDepth));

  const entryIsNotAnObject = ([key, val]) => !_.isPlainObject(val);

  let [simpleProperties, childObjects] = _.partition(Object.entries(object), entryIsNotAnObject);

  let result = simpleProperties;

  for (let depth = 1; depth < maxDepth; depth++) {

    for (let [childObjectKey, childObject] of childObjects) {
      const entries = Object.entries(childObject);
      const addParentPrefixToKey = ([key, val]) => [keyPrefixer(childObjectKey, key), val];
      const prefixedEntries = entries.map(addParentPrefixToKey);
      [simpleProperties, childObjects] = _.partition(prefixedEntries, entryIsNotAnObject);
      result = result.concat(simpleProperties);
    }
  }

  return result;
};

const test = {
  a: 'one',
  b: {
    c: 'three',
    d: {
      e: {
        f: ['six', 'six'],
        g: 7
      }
    }
  }
};

console.log(flattenEntries(test, 10));
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.min.js"></script>

The following solution handles the case for null values and arrays.

let user = {
  name: "John Doe",
  address: {
    personal: {
      city: "Haridwar",
      state: "Uttrakhand",
      area: "Majra",
    },
    office: {
      city: "Hyderabad",
      area: {
        landmark: "Hi Tech",
        pincode: [12321, 23414],
        lane: null
      }
    }
  }
}


function more_magic() {
  let ans = {};
  let magic = function (obj, parent) {
    for (let key in obj) {
      if (typeof obj[key] === "object" && obj[key] !== null && Array.isArray(obj[key]) === false) {
        magic(obj[key], parent + "_" + key);
      } else {
        ans[parent + "_" + key] = obj[key];
      }
    }
  }
  magic(user, "user");
  return ans;
}
console.log(more_magic())

I needed something similar that would deep flatten objects recursively into a string, but with customizations on different provided matchers. Based on some examples here this is what I finally ended up with, using lodash and some lodash fp functions. This way you can reduce true down to just "T" and undefined down to just "U". The matchers will need a matching key with the process. Everything else is just processed with String(item)

import _ from "lodash"

import flow from "lodash/fp/flow"
import some from "lodash/fp/some"
import reduce from "lodash/fp/reduce" 
....

const deepValuesToComparableString = items => {
  let matchers = {
    u: _.isUndefined, n: _.isNull,
    b: _.isBoolean, o: _.isObject,
    a: _.isArray, z: _.stubTrue
  }
  let process = {
    u: _.constant("U"), n: _.constant("N"),
    b: b => b ? "T" : "F", o: flow(_.flatMapDeep, _.values),
    a: _.flattenDeep, z: String
   }
  let convertForMatch = _.cond(_.zip(_.values(matchers), _.values(process)))
  let stillHasDepth = some(matchers.o || matchers.a)
  let valuesFor = reduce((acc, item) => [...acc, ...convertForMatch(item)], [])
  let flatReduceValues = reduce((acc, item) => [
    ...acc, ...stillHasDepth(item) 
      ? valuesFor(flatReduceValues(valuesFor(item))) 
      : valuesFor(item)
  ], [])
  return flatReduceValues(items).join("")
}

unit test:

test("it converts a 1d array of models into a string", () => {
  let someArrayData = [
    new TestDataClass({ someStr: "Test1", someOtherStr: "Abc", someNum: 1, someBool: false, someObjWithArrField: { someField: "some obj field", subRows: [{someSubRowField: "123", someOtherSubRowField: "testA"  }]}}),
    new TestDataClass({ someStr: "Test2", someOtherStr: undefined, someNum: 2, someBool: true,  someObjWithArrField: { someField: "obj field 2", subRows: [{someSubRowField: "234", someOtherSubRowField: "test B" }]}}),
    new TestDataClass({ someStr: "Sfds3", someOtherStr: "GGG", someNum: 3, someBool: null,  someObjWithArrField: { someField: "some field 3", subRows: [{someSubRowField: "456", someOtherSubRowField: "test C" }]}}),
  ]
  let result = deepValuesToComparableString(someArrayData)
  let expectedStr = "Test1Abc1Fsome obj field123testATest2U2Tobj field 2234test BSfds3GGG3Nsome field 3456test C"
  expect(result).toEqual(expectedStr)
})

I came here because I needed to spread an object as a tree into its property paths (complete paths to leaves in depth-first traversal), but couldn't find it in other answers, so here's my own solution:

Test Input

const obj = {
  x: 1,
  y: "hello",
  z: {
    _id: 5,
    "never.mind": [1, 2, 3],
    a: { "o]k": true, aA: 0 },
    B: null,
    C: [],
    D00d: {},
  },
};

Expected Output (in human readable form)

x : 1
y : "hello"
z ---> _id : 5
z ---> never.mind : [1, 2, 3]
z ---> a ---> o]k : true
z ---> a ---> aA : 0
z ---> B : null
z ---> C : []
z ---> D00d : {}

Code

// Just a helper function, you can ignore it.
function areFlatPrimitiveArraysEqual(array1, array2) {
  if (
    !Array.isArray(array1) ||
    !Array.isArray(array2) ||
    array1.length !== array2.length
  ) {
    return false;
  }
  for (const [index, item] of array1.entries()) {
    if (array2[index] !== item) {
      return false;
    }
  }
  return true;
}

// Just a helper function, you can ignore it.
function isLiteralObject(a) {
  return !!a && a.constructor === Object;
}

function SpreadToPaths(obj) {
  // The doIt function is the recursive function that does the main job
  function doIt(obj, out, parentKeyPath) {
    const keys = obj ? Object.keys(obj) : false;
    if (!keys || !isLiteralObject(obj) || keys.length === 0) {
      const outEntry = out.find((entry) =>
        areFlatPrimitiveArraysEqual(entry.keyPath, parentKeyPath)
      );
      outEntry.value = obj;
      return;
    }
    for (let i = 0; i < keys.length; i++) {
      const newKeyPath = [...parentKeyPath, keys[i]];
      // Delete parentEntry because it has an incomplete keyPath.
      const parentEntryIndex = out.findIndex((entry) =>
        areFlatPrimitiveArraysEqual(entry.keyPath, parentKeyPath)
      );
      if (parentEntryIndex !== -1) {
        out.splice(parentEntryIndex, 1);
      }
      // Enter the new parentEntry
      out.push({
        keyPath: newKeyPath,
        value: null,
      });
      doIt(obj[keys[i]], out, newKeyPath);
    }
  }

  // Calling the doIt function with proper initial values to get the result
  const out = [];
  const parentKeyPath = [];
  doIt(obj, out, parentKeyPath);
  return out;
}

const obj = {
  x: 1,
  y: "hello",
  z: {
    _id: 5,
    "never.mind": [1, 2, 3],
    a: { "o]k": true, aA: 0 },
    B: null,
    C: [],
    D00d: {},
  },
};

console.log(SpreadToPaths(obj));

Output

[
  { keyPath: [ 'x' ], value: 1 },
  { keyPath: [ 'y' ], value: 'hello' },
  { keyPath: [ 'z', '_id' ], value: 5 },
  { keyPath: [ 'z', 'never.mind' ], value: [ 1, 2, 3 ] },
  { keyPath: [ 'z', 'a', 'o]k' ], value: true },
  { keyPath: [ 'z', 'a', 'aA' ], value: 0 },
  { keyPath: [ 'z', 'B' ], value: null },
  { keyPath: [ 'z', 'C' ], value: [] },
  { keyPath: [ 'z', 'D00d' ], value: {} }
]

Eeasier code that worked for me :

getPropertyByString(obj, propString) {
    const props = propString.split('.');
    let nestedObject = {
        ...obj
    };

    props.forEach(prop => {
        nestedObject = nestedObject[prop]
    })

    return nestedObject;
}

A method that accepts a custom property transformation (optional).

const flattenObject = (object, parentProperty, flatObject = {}, propertyTransformer = null ) => {
  const defaultPropertyTransformer = (property, parentProperty) => parentProperty ? `${parentProperty}[${property}]` : property
  propertyTransformer = propertyTransformer || defaultPropertyTransformer;

  for (let property in object){
    let transformedProperty = propertyTransformer(property, parentProperty);

    if(typeof object[property] == 'object'){
      flattenObject(object[property], transformedProperty, flatObject);
    } else {
      flatObject[transformedProperty] = object[property];
    }
  }

  return flatObject;
}
const user = { 
  name: 'Bill Clinton', 
  gender: 'M', 
  address: { 
    street: 'Bro Street 1', 
    city: 'Billville' 
  } 
}

flattenObject(user)

// Output
//
// {
//   "address[city]": "Billville",
//   "address[street]": "Bro Street 1",
//   "gender": "M",
//   "name": "Bill Clinton"
// }

Sample Input:

const myNewobj = {
  a: "bangladesh",
  b: {
    c: "pakistan",
    d: {
      e: "nepal",
      f: {
        g: "india",
      },
    },
  },
};

Sample Output:

{ a: 'bangladesh', c: 'pakistan', e: 'nepal', g: 'india' }  

My Solution:

const myNewobj = {
    a: "bangladesh",
    b: {
      c: "pakistan",
      d: {
        e: "nepal",
        f: {
          g: "india",
        },
      },
    },
  };
  
  function getValuesOfNextedObject(obj) {
    let result = [];
    for (let elt in obj) {
      if (typeof obj[elt] == "object") {
        result = result.concat(getValuesOfNextedObject(obj[elt]));
      } else {
        result.push([elt, obj[elt]]);
      }
    }
    return result;
  }
  
  var res = getValuesOfNextedObject(myNewobj)
  console.log(res)
  
  var resultObject = {};
  for (let elt of res) {
    resultObject[elt[0]] = elt[1];
  }
  console.log(resultObject);

Sample Input:

const numbers = [
    1,
    [3, [2, 8, [12, 9]]],
    [5],
    [12, [[5]]],
    [100, [23, 45]]
]

Sample Output:

const numnbers = [
    1,  3,  2, 8,  12,
    9,  5, 12, 5, 100,
    23, 45
]

Solution(1st Method):

const numbers = [
    1,
    [3, [2, 8, [12, 9]]],
    [5],
    [12, [[5]]],
    [100, [23, 45]]
]

function flattenNextedArray(arr)    {
    let numbers = [];

    for (let elt of arr) {
        if (Array.isArray(elt)) {
            numbers = numbers.concat(flattenNextedArray(elt))
        } else {
            numbers.push(elt)
        }
    }
    return numbers
}


var flatten = flattenNextedArray(numbers)
console.log(flatten)

Solution(2nd Method):

const numbers = [
    1,
    [3, [2, 8, [12, 9]]],
    [5],
    [12, [[5]]],
    [100, [23, 45]]
]

var flatten = numbers.flat(Infinity)
console.log(flatten)

10 Lines of code for the rescue here (speaking of the function alone)

let o = {
  a: {
    b: 1,
    c: {d:2}
  },
  e: 3,
  f: [4,5,6]
};

let res = []; //Vec<&str, String|Number>
function flatten_obj(obj, ok="") {
  for (let [k,v] of Object.entries(obj)) {
    if (typeof(v) === "object") {
      flatten_obj(v, ok+k+".");
    } else {
      res.push([ok+k, v]);
    }
  }
}

flatten_obj(o);
console.log(res);

Pragmatic Solution 2022

Many beautiful solutions here. Some I find a little ambitious. That's probably because I find recursions great but don't usually understand them straight away. My personal problem ;-) Since you only have one level here, I would use the good old foreach loop.

const nestyObject = { 0: [1,2,3,4], a: ['b','c','d','e'] };

const arr = []
Object.keys(nestyObject).forEach(key => {
  const left = key;
  const right = nestyObject[key];
  arr.push([left, ...right]);
});

console.log(arr)

本文标签: javascriptBest way to flatten JS object (keys and values) to a single depth arrayStack Overflow