Skip to content

Instantly share code, notes, and snippets.

@jemgold
Last active March 1, 2016 08:33
Show Gist options
  • Save jemgold/c176be598141c871be1a to your computer and use it in GitHub Desktop.
Save jemgold/c176be598141c871be1a to your computer and use it in GitHub Desktop.

Flatten / Unflatten

So I'm trying to calculate the cartesian product of object's properties

const style = {
  fontFamily: ['helvetica', 'comic sans'],
  fontWeight: [300, 700],
}

const expected = [
  { fontFamily: 'helvetica', fontWeight: 300 },
  { fontFamily: 'helvetica', fontWeight: 700 },
  { fontFamily: 'comic sans', fontWeight: 300 },
  { fontFamily: 'comic sans', fontWeight: 700 },
]

I have an algorithm that does that all nice and stuff. Then I realized I have to actually compute the cartesian property of TWO (or more) objects' properties (with the same keys in each object), returning an array of objects

const style = {
  foo: {
    fontFamily: ['helvetica', 'comic sans'],
    fontWeight: [300, 700],
  }
  bar: {
    fontFamily: ['gotham', 'proxima nova'],
    fontWeight: [300, 700],
  }
}

const expected = [
  { foo: { fontFamily: 'helvetica', fontWeight: 300 },
    bar: { fontFamily: 'gotham', fontWeight: 300 },
  },
  { foo: { fontFamily: 'helvetica', fontWeight: 300 },
    bar: { fontFamily: 'gotham', fontWeight: 700 },
  },
  { foo: { fontFamily: 'helvetica', fontWeight: 700 },
    bar: { fontFamily: 'gotham', fontWeight: 300 },
  },
  { foo: { fontFamily: 'helvetica', fontWeight: 700 },
    bar: { fontFamily: 'gotham', fontWeight: 700 },
  },
    
]

The product solver works fine; I was just trying to figure out how to make it work for deeply nested properties; easiest thing I could think of was to transform the input into a flattened object as seen in the test cases, then solve it like before, then unflatten it back into the expected structure.

With that said, do my functions look ok? They're the cleanest way I could thing of implementing it…

import expect from 'expect';
import { flatten, unflatten } from 'src/flatten';
describe('Flatten', () => {
it('flattens an object, prefixed by original keys', () => {
const input = {
foo: {
bar: 'baz',
qux: 'zip',
},
bar: {
bar: 'baz',
qux: 'zip',
},
};
const expected = {
foo_bar: 'baz',
foo_qux: 'zip',
bar_bar: 'baz',
bar_qux: 'zip',
};
expect(flatten(input)).toEqual(expected);
});
});
describe('Unflatten', () => {
it('Unflattens an object, prefixed by original keys', () => {
const input = {
foo_bar: 'baz',
foo_qux: 'zip',
bar_bar: 'baz',
bar_qux: 'zip',
};
const expected = {
foo: {
bar: 'baz',
qux: 'zip',
},
bar: {
bar: 'baz',
qux: 'zip',
},
};
expect(unflatten(input)).toEqual(expected);
});
});
import { Iteration } from './Types';
import { assoc, assocPath, merge, path, reduce, keys, split } from 'ramda';
export function flatten(state: Iteration) {
return reduce((mem1, key1) => {
return merge(
mem1,
reduce((mem2, key2) => {
return assoc(
`${key1}_${key2}`,
path([key1, key2], state),
mem2
);
}, {}, keys(path([key1], state))),
);
}, {}, keys(state));
}
export function unflatten(state) {
return reduce((mem, key) => {
return assocPath(
split('_', key),
path([key], state),
mem
);
}, {}, keys(state));
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment