Max Koretskyi
Max Koretskyi

Reputation: 105547

How to write a function that inlines object properties

I have the following object:

var ob = {
    view: {
        name: 'zpo',
        params: {
            taskId: 3,
            zuka: 'v'
        }
    }
}

I need to have this object in the following form:

{
    "view.name":"zpo",
    "view.params.taskId":3,
    "view.params.zuka":"v"
}

I have written a function that can do that, but the problem is that it requires external variables passed to it. Here is this function:

function inline(o, result, container) {
    for (var p in o) {
        if (typeof o[p] === "object") {
            inline(o[p], result.length > 0 ? result+'.'+p : p, container);
        } else {
            container[result + '.' + p] = o[p];
        }
    }
}

var ob = {
    view: {
        name: 'zpo',
        params: {
            taskId: 3,
            zuka: 'v'
        }
    }
}

var c = {};
var r = inline(ob, '', c);

Is there any way to write this function to return correct result without the need to pass result and container external variables?

Upvotes: 3

Views: 77

Answers (3)

Quentin Roy
Quentin Roy

Reputation: 7887

Here is a version that does not require any parameters.

// Return an array containing the [key, value] couples of an object.
const objEntries = o => Object.keys(o).map(k => [k, o[k]]);

// Create an object from an array of [key, value] couples.
const entriesObj = (entries, init={}) => entries.reduce((result, [key, val]) => {
  result[key] = val;
  return result;
}, init);

// Reduce on the object entries (as returned by objEntries) with an empty object as
// initialiser.
const inline = (o) => objEntries(o).reduce((result, [key, val]) => {
  if(val instanceof Object){
    // If the value is an object, recursively inline it.
    const inlineVal = inline(val);
    // Prefix each property names of inlineVal with the key of val and add the
    // properties to the result object.
    entriesObj(
      objEntries(inlineVal).map(([subK, subVal]) => [key + '.' + subK, subVal]),
      result
    );
  } else {
    // If val is not an object, just add it to the result as is.
    result[key] = val;
  }
  // Return the result.
  return result;
}, {});

var ob = {
    view: {
        name: 'zpo',
        params: {
            taskId: 3,
            zuka: 'v'
        }
    }
}

var r = inline(ob);
console.log(r);

I used arrow functions and destructuring. Old browsers won't support it. If you need to support them, just replace the arrow functions with regular functions and manually destructure the arguments.

Upvotes: 0

Jordan Davidson
Jordan Davidson

Reputation: 419

javascript is awesome!

function inline(o, result, container) {
  result = result || '';
  container = container || {};
  for (var p in o) {
    if (typeof o[p] === "object") {
      inline(o[p], result.length > 0 ? result+'.'+p : p, container);
    } else {
      container[result + '.' + p] = o[p];
    }
  }
}

var r = inline(ob);

Upvotes: 0

malifa
malifa

Reputation: 8165

If i understood you correctly, you want to avoid to call your inline() function with "empty" params.

You could catch this case in your function directly:

function inline(o, result, container) {
    result = result || '';
    container = container || {};
    ...
}

var r = inline(ob);

you would still need this params for the recursive part of your function.

Upvotes: 1

Related Questions