0

I am trying to solve a specific problem using functional programming. My guess is that a fold should do the job, but so far the solution has eluded me.

Starting from a dot-separated string like "a.b.c" I want to build a Javascript object which in JS literal notation would look like:

obj = {a:{b:{c:"whatever"}}}

The algorithm should accept a seed object to start with. In the previous example the seed would be {}.

If I provided {a:{f:"whatever else"}} as seed, the result would be

{a:{f:"whatever else",b:{c:"whatever"}}}

I hope my description is clear enough. I am not talking about string manipulation. I want to create proper objects.

I am using Javascript because that's the language where this real-world problem has arisen and where I will implement the FP solution which I hope to find by asking here.

EDIT: the main issue I am trying to tackle is how to avoid mutable objects. JS is somehow too lenient about adding/removing attributes and in this case I want to be sure that there will be no side effects during the run of the FP routine.

4
  • Why do you focus on FP? Do you have a solution without FP already? Please show us what you've tried and where you're stuck. Commented Apr 4, 2014 at 14:56
  • I focus on FP because I want to exploit immutability. The non-FP solution is an iterator that enters the seed and mutates it. I am trying a solution with fold right. I have a result that works fine with seed {} but fails in case of complex seeds. Commented Apr 5, 2014 at 16:26
  • Gotta find my current fold right solution and post it here. Sorry, too little time this afternoon :-) Commented Apr 5, 2014 at 16:38
  • You mean for the {a:{f:"whatever else"}} example, you want to return a copy instead of mutating the seed? Commented Apr 5, 2014 at 17:21

2 Answers 2

2
var seed = {},
    str = "a.b.c";
str.split(".").reduce(function(o, p) {
    return p in o ? o[p] : (o[p] = {});
}, seed);

console.log(seed); // {"a":{"b":{"c":{}}}}
Sign up to request clarification or add additional context in comments.

5 Comments

This solution, letting aside the mutations, shows me the power of folds in manipulating accumulators other than lists. In a way, there is no difference between cons-ing a head in front of an accumulator list and adding one more level deep down an accumulator object.
...and the way you prepare the accumulator for the next iteration thanks to the self-executing function is absolutely BRILLIANT!
self-executing function? There's no IEFE here.
Well, now you're mentioning it. How would you call the (o[p]={}) idiom? I've tried to reproduce it with (function(){ o[p] = {};})() and alikes but I see it's not quite the same. Your code returns o[p] and that baffles me.
Ok, I got it. Didn't know that assignments return stuff. I'd say they returned undefined, but it makes more sense this way. JS is still surprising me after all these years...
1

A fully functional variant:

function traverse(tree, path, leftover) {
    if (!tree || !path.length)
        return leftover(path);
    var ntree = {};
    for (var p in tree)
        ntree[p] = tree[p];
    ntree[path[0]] = traverse(tree[path[0]], path.slice(1), leftover);
    return ntree;
}
function create(path, value) {
    if (!path.length)
        return value;
    var tree = {};
    tree[path[0]] = create(path.slice(1), value);
    return tree;
}

function set(tree, pathstring, value) {
    return traverse(tree, pathstring.split("."), function(path) {
        return create(path, value);
    });
}

var seed = {a:{f:"whatever else"}};
var obj = set(seed, "a.b.c", "whatever")
    // {"a":{"f":"whatever else","b":{"c":"whatever"}}}
set({}, "a.b.c", "whatever")
    // {"a":{"b":{"c":"whatever"}}}

1 Comment

OK, rather instructive example. The ntree[p] = tree[p] thing is a shallow copy, but I know how to handle that. The construction ntree[path[0]] = traverse(tree[path[0]],...); return ntree; is a precious takeaway. I reckon you found all this quite simple, but imho it's not. Thank you...

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.