Recursively looping through an object to build a property list

JavascriptObject

Javascript Problem Overview


Situation: I have a large object containing multiple sub and sub-sub objects, with properties containing multiple datatypes. For our purposes, this object looks something like this:

var object = {
	aProperty: {
		aSetting1: 1,
		aSetting2: 2,
		aSetting3: 3,
		aSetting4: 4,
		aSetting5: 5
	},
	bProperty: {
		bSetting1: {
			bPropertySubSetting : true
		},
		bSetting2: "bString"
	},
	cProperty: {
		cSetting: "cString"
	}
}

I need to loop through this object and build a list of the keys that shows the hierarchy, so the list ends up looking like this:

aProperty.aSetting1
aProperty.aSetting2
aProperty.aSetting3
aProperty.aSetting4
aProperty.aSetting5
bProperty.bSetting1.bPropertySubSetting
bProperty.bSetting2
cProperty.cSetting

I've got this function, which does loop through the object and spit out the keys, but not hierarchically:

function iterate(obj) {
	for (var property in obj) {
		if (obj.hasOwnProperty(property)) {
			if (typeof obj[property] == "object") {
				iterate(obj[property]);
			}
			else {
				console.log(property + "   " + obj[property]);
			}
		}
	}
}

Can somebody let me know how to do this? Here's a jsfiddle for you to mess with: http://jsfiddle.net/tbynA/

Javascript Solutions


Solution 1 - Javascript

I made a FIDDLE for you. I am storing a stack string and then output it, if the property is of primitive type:

function iterate(obj, stack) {
        for (var property in obj) {
            if (obj.hasOwnProperty(property)) {
                if (typeof obj[property] == "object") {
                    iterate(obj[property], stack + '.' + property);
                } else {
                    console.log(property + "   " + obj[property]);
                    $('#output').append($("<div/>").text(stack + '.' + property))
                }
            }
        }
    }

iterate(object, '')

UPDATE (17/01/2019) - <There used to be a different implementation, but it didn't work. See this answer for a prettier solution :)>

Solution 2 - Javascript

The solution from Artyom Neustroev does not work on complex objects, so here is a working solution based on his idea:

function propertiesToArray(obj) {
  const isObject = val =>
    val && typeof val === 'object' && !Array.isArray(val);

  const addDelimiter = (a, b) =>
    a ? `${a}.${b}` : b;

  const paths = (obj = {}, head = '') => {
    return Object.entries(obj)
      .reduce((product, [key, value]) => 
        {
          let fullPath = addDelimiter(head, key)
          return isObject(value) ?
            product.concat(paths(value, fullPath))
          : product.concat(fullPath)
        }, []);
  }

  return paths(obj);
}
  
const foo = {foo: {bar: {baz: undefined}, fub: 'goz', bag: {zar: {zaz: null}, raz: 3}}}
const result = propertiesToArray(foo)
console.log(result)

Solution 3 - Javascript

You'll run into issues with this if the object has loop in its object graph, e.g something like:

var object = {
    aProperty: {
        aSetting1: 1
    },
};
object.ref = object;

In that case you might want to keep references of objects you've already walked through & exclude them from the iteration.

Also you can run into an issue if the object graph is too deep like:

var object = {
  a: { b: { c: { ... }} }
};

You'll get too many recursive calls error. Both can be avoided:

function iterate(obj) {
    var walked = [];
    var stack = [{obj: obj, stack: ''}];
    while(stack.length > 0)
    {
        var item = stack.pop();
        var obj = item.obj;
        for (var property in obj) {
            if (obj.hasOwnProperty(property)) {
                if (typeof obj[property] == "object") {
                  var alreadyFound = false;
                  for(var i = 0; i < walked.length; i++)
                  {
                    if (walked[i] === obj[property])
                    {
                      alreadyFound = true;
                      break;
                    }
                  }
                  if (!alreadyFound)
                  {
                    walked.push(obj[property]);
                    stack.push({obj: obj[property], stack: item.stack + '.' + property});
                  }
                }
                else
                {
                    console.log(item.stack + '.' + property + "=" + obj[property]);
                }
            }
        }
    }
}

iterate(object); 

Solution 4 - Javascript

https://github.com/hughsk/flat

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
// }

Just loop to get the indexes after.

Solution 5 - Javascript

You don't need recursion!

The following function function which will output the entries in the order of least deep to the most deep with the value of the key as a [key, value] array.

function deepEntries( obj ){
    'use-strict';
    var allkeys, curKey = '[', len = 0, i = -1, entryK;

    function formatKeys( entries ){
       entryK = entries.length;
       len += entries.length;
       while (entryK--)
         entries[entryK][0] = curKey+JSON.stringify(entries[entryK][0])+']';
       return entries;
    }
    allkeys = formatKeys( Object.entries(obj) );

    while (++i !== len)
        if (typeof allkeys[i][1] === 'object' && allkeys[i][1] !== null){
            curKey = allkeys[i][0] + '[';
            Array.prototype.push.apply(
                allkeys,
                formatKeys( Object.entries(allkeys[i][1]) )
            );
        }
    return allkeys;
}

Then, to output the kind of results you are looking for, just use this.

function stringifyEntries(allkeys){
    return allkeys.reduce(function(acc, x){
        return acc+((acc&&'\n')+x[0])
    }, '');
};

If your interested in the technical bits, then this is how it works. It works by getting the Object.entries of the obj object you passed and puts them in array allkeys. Then, going from the beggining of allkeys to the end, if it finds that one of allkeys entries value's is an object then it gets that entrie's key as curKey, and prefixes each of its own entries keys with curKey before it pushes that resulting array onto the end of allkeys. Then, it adds the number of entries added to allkeys to the target length so that it will also go over those newly added keys too.

For example, observe the following:

<script>
var object = {
    aProperty: {
        aSetting1: 1,
        aSetting2: 2,
        aSetting3: 3,
        aSetting4: 4,
        aSetting5: 5
    },
    bProperty: {
        bSetting1: {
            bPropertySubSetting : true
        },
        bSetting2: "bString"
    },
    cProperty: {
        cSetting: "cString"
    }
}
document.write(
    '<pre>' + stringifyEntries( deepEntries(object) ) + '</pre>'
);
function deepEntries( obj ){//debugger;
    'use-strict';
    var allkeys, curKey = '[', len = 0, i = -1, entryK;

    function formatKeys( entries ){
       entryK = entries.length;
       len += entries.length;
       while (entryK--)
         entries[entryK][0] = curKey+JSON.stringify(entries[entryK][0])+']';
       return entries;
    }
    allkeys = formatKeys( Object.entries(obj) );

    while (++i !== len)
        if (typeof allkeys[i][1] === 'object' && allkeys[i][1] !== null){
            curKey = allkeys[i][0] + '[';
            Array.prototype.push.apply(
                allkeys,
                formatKeys( Object.entries(allkeys[i][1]) )
            );
        }
    return allkeys;
}
function stringifyEntries(allkeys){
    return allkeys.reduce(function(acc, x){
        return acc+((acc&&'\n')+x[0])
    }, '');
};
</script>

Or, if you only want the properties, and not the objects that have properties, then you can filter then out like so:

deepEntries(object).filter(function(x){return typeof x[1] !== 'object'});

Example:

<script>
var object = {
    aProperty: {
        aSetting1: 1,
        aSetting2: 2,
        aSetting3: 3,
        aSetting4: 4,
        aSetting5: 5
    },
    bProperty: {
        bSetting1: {
            bPropertySubSetting : true
        },
        bSetting2: "bString"
    },
    cProperty: {
        cSetting: "cString"
    }
}
document.write('<pre>' + stringifyEntries(
    deepEntries(object).filter(function(x){
       return typeof x[1] !== 'object';
    })
) + '</pre>');
function deepEntries( obj ){//debugger;
    'use-strict';
    var allkeys, curKey = '[', len = 0, i = -1, entryK;

    function formatKeys( entries ){
       entryK = entries.length;
       len += entries.length;
       while (entryK--)
         entries[entryK][0] = curKey+JSON.stringify(entries[entryK][0])+']';
       return entries;
    }
    allkeys = formatKeys( Object.entries(obj) );

    while (++i !== len)
        if (typeof allkeys[i][1] === 'object' && allkeys[i][1] !== null){
            curKey = allkeys[i][0] + '[';
            Array.prototype.push.apply(
                allkeys,
                formatKeys( Object.entries(allkeys[i][1]) )
            );
        }
    return allkeys;
}
function stringifyEntries(allkeys){
    return allkeys.reduce(function(acc, x){
        return acc+((acc&&'\n')+x[0])
    }, '');
};
</script>

Browser Compatibility
The above solution will not work in IE, rather it will only work in Edge because it uses the Object.entries function. If you need IE9+ support, then simply add the following Object.entries polyfill to your code. If you, for some reason beyond me, actually do need IE6+ support, then you will also need an Object.keys and JSON.stringify polyfill (neither listed here, so find it somewhere else).

if (!Object.entries)
  Object.entries = function( obj ){
    var ownProps = Object.keys( obj ),
        i = ownProps.length,
        resArray = new Array(i); // preallocate the Array
    while (i--)
      resArray[i] = [ownProps[i], obj[ownProps[i]]];
    
    return resArray;
  };

Solution 6 - Javascript

With a little help from lodash...

/**
 * For object (or array) `obj`, recursively search all keys
 * and generate unique paths for every key in the tree.
 * @param {Object} obj
 * @param {String} prev
 */
export const getUniqueKeyPaths = (obj, prev = '') => _.flatten(
  Object
  .entries(obj)
  .map(entry => {
    const [k, v] = entry
    if (v !== null && typeof v === 'object') {
      const newK = prev ? `${prev}.${k}` : `${k}`
      // Must include the prev and current k before going recursive so we don't lose keys whose values are arrays or objects
      return [newK, ...getUniqueKeyPaths(v, newK)]
    }
    return `${prev}.${k}`
  })
)

Solution 7 - Javascript

This version is packed in a function that accepts a custom delimiter, filter, and returns a flat dictionary:

function flatten(source, delimiter, filter) {
  var result = {}
  ;(function flat(obj, stack) {
    Object.keys(obj).forEach(function(k) {
      var s = stack.concat([k])
      var v = obj[k]
      if (filter && filter(k, v)) return
      if (typeof v === 'object') flat(v, s)
      else result[s.join(delimiter)] = v
    })
  })(source, [])
  return result
}

var obj = {
  a: 1,
  b: {
    c: 2
  }
}
flatten(obj)
// <- Object {a: 1, b.c: 2}
flatten(obj, '/')
// <- Object {a: 1, b/c: 2}
flatten(obj, '/', function(k, v) { return k.startsWith('a') })
// <- Object {b/c: 2}

Solution 8 - Javascript

UPDATE: JUST USE JSON.stringify to print objects on screen!

All you need is this line:

document.body.innerHTML = '<pre>' + JSON.stringify(ObjectWithSubObjects, null, "\t") + '</pre>';

This is my older version of printing objects recursively on screen:

 var previousStack = '';
    var output = '';
    function objToString(obj, stack) {
        for (var property in obj) {
            var tab = '&nbsp;&nbsp;&nbsp;&nbsp;';
            if (obj.hasOwnProperty(property)) {
                if (typeof obj[property] === 'object' && typeof stack === 'undefined') {
                    config = objToString(obj[property], property);
                } else {
                    if (typeof stack !== 'undefined' && stack !== null && stack === previousStack) {
                        output = output.substring(0, output.length - 1);  // remove last }
                        output += tab + '<span>' + property + ': ' + obj[property] + '</span><br />'; // insert property
                        output += '}';   // add last } again
                    } else {
                        if (typeof stack !== 'undefined') {
                            output += stack + ': {  <br />' + tab;
                        }
                        output += '<span>' + property + ': ' + obj[property] + '</span><br />';
                        if (typeof stack !== 'undefined') {
                            output += '}';
                        }
                    }
                    previousStack = stack;
                }
            }
        }
        return output;
    }

Usage:

document.body.innerHTML = objToString(ObjectWithSubObjects);

Example output:

cache: false
position: fixed
effect: { 
    fade: false
    fall: true
}

Obviously this can be improved by adding comma's when needed and quotes from string values. But this was good enough for my case.

Solution 9 - Javascript

This solution won't fail if there is a null value anywhere.

function recursiveKeys(obj) {
  const helper = (obj, prefix, acc) => {
    if ("" !== prefix) acc.push(prefix);
    if (typeof obj === "object" && obj !== null) {
      if (Array.isArray(obj)) {
        for (let k = 0; k < obj.length; k++) {
          helper(obj[k], prefix + "[" + k + "]", acc);
        }
      } else {
        const keys = Object.keys(obj);
        keys.forEach((k) => {
          helper(obj[k], prefix + "." + k, acc);
        });
      }
    }
    return acc;
  };
  return helper(obj, "", []);
}

Called like this

const obj = {
  name: "Sherlock Holmes",
  address: { street: "221B Baker Street", city: "London" },
  fruits: ["Orange", "Apple"],
};
recursiveKeys(obj);

it returns this

[  ".name",  ".address",  ".address.street",  ".address.city",  ".fruits",  ".fruits[0]",  ".fruits[1]",]

Solution 10 - Javascript

Suppose that you have a JSON object like:

var example = {
    "prop1": "value1",
    "prop2": [ "value2_0", "value2_1"],
    "prop3": {
         "prop3_1": "value3_1"
    }
}

The wrong way to iterate through its 'properties':

function recursivelyIterateProperties(jsonObject) {
    for (var prop in Object.keys(jsonObject)) {
        console.log(prop);
        recursivelyIterateProperties(jsonObject[prop]);
    }
}

You might be surprised of seeing the console logging 0, 1, etc. when iterating through the properties of prop1 and prop2 and of prop3_1. Those objects are sequences, and the indexes of a sequence are properties of that object in Javascript.

A better way to recursively iterate through a JSON object properties would be to first check if that object is a sequence or not:

function recursivelyIterateProperties(jsonObject) {
    for (var prop in Object.keys(jsonObject)) {
        console.log(prop);
        if (!(typeof(jsonObject[prop]) === 'string')
            && !(jsonObject[prop] instanceof Array)) {
                recursivelyIterateProperties(jsonObject[prop]);

            }
     }
}

If you want to find properties inside of objects in arrays, then do the following:

function recursivelyIterateProperties(jsonObject) {
    
    if (jsonObject instanceof Array) {
        for (var i = 0; i < jsonObject.length; ++i) {
            recursivelyIterateProperties(jsonObject[i])
        }
    }
    else if (typeof(jsonObject) === 'object') {
        for (var prop in Object.keys(jsonObject)) {
            console.log(prop);
            if (!(typeof(jsonObject[prop]) === 'string')) {
                recursivelyIterateProperties(jsonObject[prop]);
            }
        }
    }
}

Solution 11 - Javascript

An improved solution with filtering possibilities. This result is more convenient as you can refer any object property directly with array paths like:

> ["aProperty.aSetting1", "aProperty.aSetting2", "aProperty.aSetting3", "aProperty.aSetting4", "aProperty.aSetting5", "bProperty.bSetting1.bPropertySubSetting", "bProperty.bSetting2", "cProperty.cSetting"]

 /**
 * Recursively searches for properties in a given object. 
 * Ignores possible prototype endless enclosures. 
 * Can list either all properties or filtered by key name.
 *
 * @param {Object} object Object with properties.
 * @param {String} key Property key name to search for. Empty string to 
 *                     get all properties list .
 * @returns {String} Paths to properties from object root.
 */
function getPropertiesByKey(object, key) {

  var paths = [
  ];

  iterate(
    object,
    "");

  return paths;

  /**
   * Single object iteration. Accumulates to an outer 'paths' array.
   */
  function iterate(object, path) {
    var chainedPath;

    for (var property in object) {
      if (object.hasOwnProperty(property)) {

        chainedPath =
          path.length > 0 ?
          path + "." + property :
          path + property;

        if (typeof object[property] == "object") {

          iterate(
            object[property],
            chainedPath,
            chainedPath);
        } else if (
          property === key ||
          key.length === 0) {

          paths.push(
            chainedPath);
        }
      }
    }

    return paths;
  }
}

Solution 12 - Javascript

Solution to flatten properties and arrays as well.

Example input:

{
  obj1: {
    prop1: "value1",
    prop2: "value2"
  },
  arr1: [
    "value1",
    "value2"
  ]
}

Output:

"arr1[0]": "value1"
"arr1[1]": "value2"
"obj1.prop1": "value1"
"obj1.prop2": "value2"

Source code:

flatten(object, path = '', res = undefined) {
      if (!Array.isArray(res)) {
          res = [];
      }
      if (object !== null && typeof object === 'object') {
          if (Array.isArray(object)) {
              for (let i = 0; i < object.length; i++) {
                  this.flatten(object[i], path + '[' + i + ']', res)
              }
          } else {
              const keys = Object.keys(object)
              for (let i = 0; i < keys.length; i++) {
                  const key = keys[i]
                  this.flatten(object[key], path ? path + '.' + key : key, res)
              }
          }
      } else {
          if (path) {
              res[path] = object
          }
      }
      return res
  }

Solution 13 - Javascript

Here is a simple solution. This is a late answer but may be simple one-

const data = {
  city: 'foo',
  year: 2020,
  person: {
    name: {
      firstName: 'john',
      lastName: 'doe'
    },
    age: 20,
    type: {
      a: 2,
      b: 3,
      c: {
        d: 4,
        e: 5
      }
    }
  },
}

function getKey(obj, res = [], parent = '') {
  const keys = Object.keys(obj);
  
  /** Loop throw the object keys and check if there is any object there */
  keys.forEach(key => {
    if (typeof obj[key] !== 'object') {
      // Generate the heirarchy
      parent ? res.push(`${parent}.${key}`) : res.push(key);
    } else {
      // If object found then recursively call the function with updpated parent
      let newParent = parent ? `${parent}.${key}` : key;
      getKey(obj[key], res, newParent);
    }
    
  });
}

const result = [];

getKey(data, result, '');

console.log(result);

.as-console-wrapper{min-height: 100%!important; top: 0}

Solution 14 - Javascript

This function can handle objects containing both objects and arrays of objects. Result will be one line per each single item of the object, representing its full path in the structure.

Tested with http://haya2now.jp/data/data.json

Example result: geometry[6].obs[5].hayabusa2.delay_from

function iterate(obj, stack, prevType) {
    for (var property in obj) {
        if ( Array.isArray(obj[property]) ) {
        	//console.log(property , "(L="  + obj[property].length + ") is an array  with parent ", prevType, stack);
        	iterate(obj[property], stack  + property , "array");
        } else {
        	if ((typeof obj[property] != "string")  && (typeof obj[property] != "number"))  {
        		if(prevType == "array") {
        			//console.log(stack + "["  + property + "] is an object, item of " , prevType, stack);
        			iterate(obj[property], stack + "["  +property + "]." , "object");
        		} else {
					//console.log(stack +    property  , "is " , typeof obj[property] , " with parent ", prevType, stack );
					iterate(obj[property], stack  + property + ".", "object");
				}	
			} else {
        		if(prevType == "array") {
        			console.log(stack + "["  + property + "] =  "+  obj[property]);
        			
        		} else {
					console.log(stack +    property  , " =  " ,  obj[property] );						
				}	
			}
        }
    


    }
}

iterate(object, '', "File")
console.log(object);

Solution 15 - Javascript

You can use a recursive Object.keys to achieve that.

var keys = []

const findKeys = (object, prevKey = '') => {
  Object.keys(object).forEach((key) => {
    const nestedKey = prevKey === '' ? key : `${prevKey}.${key}`

    if (typeof object[key] !== 'object') return keys.push(nestedKey)

    findKeys(object[key], nestedKey)
  })
}

findKeys(object)

console.log(keys)

Which results in this array

[  "aProperty.aSetting1",  "aProperty.aSetting2",  "aProperty.aSetting3",  "aProperty.aSetting4",  "aProperty.aSetting5",  "bProperty.bSetting1.bPropertySubSetting",  "bProperty.bSetting2",  "cProperty.cSetting"]

To test, you can provide your object:

object = {
  aProperty: {
    aSetting1: 1,
    aSetting2: 2,
    aSetting3: 3,
    aSetting4: 4,
    aSetting5: 5
  },
  bProperty: {
    bSetting1: {
      bPropertySubSetting: true
    },
    bSetting2: "bString"
  },
  cProperty: {
    cSetting: "cString"
  }
}

Solution 16 - Javascript

I'll provide a solution too, using recursion. Commented lines to clarify things.

It works well for its purpose right now.

// works only if the value is a dictionary or something specified below, and adds all keys in nested objects and outputs them

const example = {
  city: "foo",
  year: 2020,
  person: {
    name: "foo",
    age: 20,
    deeper: {
      even_deeper: {
        key: "value", 
        arr: [1, 2, {
          a: 1,
          b: 2
        }]
      }
    }
  },
};

var flat  =  [];    // store keys
var depth =  0;     // depth, used later
var path  =  "obj"; // base path to be added onto, specified using the second parameter of flatKeys 

let flatKeys = (t, name) => {
  path = name ? name : path;  // if specified, set the path 
  for (const k in t) {
    const v = t[k];
    let type = typeof v;      // store the type value's type
    switch (type) {  
      case "string":          // these are the specified cases for which a key will be added,
      case "number":          // specify more if you want
      case "array" :
        flat.push(path + "." + k);  // add the complete path to the array
        break;
      case "object":
        flat.push(path + "." + k)
        path += "." + k;
        flatKeys(v);
        break;
    }
  }
  return flat;
};

let flattened = flatKeys(example, "example"); // the second argument is what the root path should be (for convenience)
console.log(flattened, "keys: " + flattened.length);

Solution 17 - Javascript

A simple path global variable across each recursive call does the trick for me !

var object = {
  aProperty: {
    aSetting1: 1,
    aSetting2: 2,
    aSetting3: 3,
    aSetting4: 4,
    aSetting5: 5
  },
  bProperty: {
    bSetting1: {
      bPropertySubSetting: true
    },
    bSetting2: "bString"
  },
  cProperty: {
    cSetting: "cString"
  }
}

function iterate(obj, path = []) {
  for (var property in obj) {
    if (obj.hasOwnProperty(property)) {
      if (typeof obj[property] == "object") {
        let curpath = [...path, property];
        iterate(obj[property], curpath);
      } else {
        console.log(path.join('.') + '.' + property + "   " + obj[property]);
        $('#output').append($("<div/>").text(path.join('.') + '.' + property))
      }
    }
  }
}

iterate(object);

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.1/jquery.min.js"></script>
<div id='output'></div>

Solution 18 - Javascript

matjaz's answer was almost perfect for me, except I have arrays in my Json so I did this:

function propertiesToArray(obj) {
  const isObject = val =>
    val && typeof val === 'object' && !Array.isArray(val);

  const addDelimiter = (a, b) =>
    a ? `${a}.${b}` : b;

  const paths = (obj = {}, head = '') => {
    return Object.entries(obj)
      .reduce((product, [key, value]) => 
        {
          let fullPath = addDelimiter(head, key)
          return isObject(value) ?
            product.concat(paths(value, fullPath))
            : Array.isArray(value) ? 
                product.concat(addDelimiter(key, propertiesToArray(value)))
              : product.concat(fullPath)
        }, []);
  }

  return paths(obj);
}

const foo = {foo: {bar: {baz: undefined}, fub: 'goz', arr: [{'aro1':'bla1','bro2':'bla2','cro3':'bla3'}], bag: {zar: {zaz: null}, raz: 3}}}
const result = propertiesToArray(foo)
console.log(result)

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionJakeView Question on Stackoverflow
Solution 1 - JavascriptArtyom NeustroevView Answer on Stackoverflow
Solution 2 - JavascriptMatjazView Answer on Stackoverflow
Solution 3 - JavascriptOndrej SvejdarView Answer on Stackoverflow
Solution 4 - JavascriptMatthieu DrulaView Answer on Stackoverflow
Solution 5 - JavascriptJack GView Answer on Stackoverflow
Solution 6 - JavascriptZCaceresView Answer on Stackoverflow
Solution 7 - JavascriptHanumanView Answer on Stackoverflow
Solution 8 - JavascriptFlorisView Answer on Stackoverflow
Solution 9 - JavascriptmikeyreillyView Answer on Stackoverflow
Solution 10 - JavascriptJadiel de ArmasView Answer on Stackoverflow
Solution 11 - JavascriptZonView Answer on Stackoverflow
Solution 12 - JavascriptSergey GurinView Answer on Stackoverflow
Solution 13 - JavascriptSajeeb AhamedView Answer on Stackoverflow
Solution 14 - JavascriptjumpjackView Answer on Stackoverflow
Solution 15 - JavascriptVictorView Answer on Stackoverflow
Solution 16 - Javascriptun-indexView Answer on Stackoverflow
Solution 17 - JavascriptRimika DattaView Answer on Stackoverflow
Solution 18 - JavascriptGil CohenView Answer on Stackoverflow