Last active
June 26, 2019 08:44
-
-
Save 3rdp/7204a7dbb01da2abb77a34499c4e1964 to your computer and use it in GitHub Desktop.
Hitting hobbits for the first time
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** You need to add right body parts */ | |
const asymHobbitBodyParts = [{name: "head", size: 3}, | |
{name: "left-eye", size: 1}, | |
{name: "left-ear", size: 1}, | |
{name: "mouth", size: 1}, | |
{name: "nose", size: 1}, | |
{name: "neck", size: 2}, | |
{name: "left-shoulder", size: 3}, | |
{name: "left-upper-arm", size: 3}, | |
{name: "chest", size: 10}, | |
{name: "back", size: 10}, | |
{name: "left-forearm", size: 3}, | |
{name: "abdomen", size: 6}, | |
{name: "left-kidney", size: 1}, | |
{name: "left-hand", size: 2}, | |
{name: "left-knee", size: 2}, | |
{name: "left-thigh", size: 4}, | |
{name: "left-lower-leg", size: 3}, | |
{name: "left-achilles", size: 1}, | |
{name: "left-foot", size: 2}] | |
/** How would I probably solve this problem in Javascript */ | |
const regexLeft = /^left-/ | |
const rightBodyParts = asymHobbitBodyParts.map(part => { | |
if (regexLeft.test(part.name)) | |
return Object.assign({}, part, | |
{ name: part.name.replace(regexLeft, 'right-') }) | |
}) | |
const symmetric = asymHobbitBodyParts.concat(rightBodyParts.filter(Boolean)) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
;; Brave Clojure takes a slightly different approach | |
;; This code doesn't check for a 'left-' in a name | |
;; Instead, and this is pure genius, it removes a duplicate object, like when name is nose, by using set sctructure | |
(defn matching-part | |
[part] | |
{:name (clojure.string/replace (:name part) #"^left-" "right-") | |
:size (:size part)}) | |
(defn symmetrize-body-parts | |
"Expects a seq of maps that have a :name and :size" | |
[asym-body-parts] | |
(loop [remaining-asym-parts asym-body-parts | |
final-body-parts []] | |
(if (empty? remaining-asym-parts) | |
final-body-parts | |
(let [[part & remaining] remaining-asym-parts] | |
(recur remaining | |
(into final-body-parts | |
(set [part (matching-part part)]))))))) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** You need to add right body parts */ | |
const asymHobbitBodyParts = [{name: "head", size: 3}, | |
{name: "left-eye", size: 1}, | |
{name: "left-ear", size: 1}, | |
{name: "mouth", size: 1}, | |
{name: "nose", size: 1}, | |
{name: "neck", size: 2}, | |
{name: "left-shoulder", size: 3}, | |
{name: "left-upper-arm", size: 3}, | |
{name: "chest", size: 10}, | |
{name: "back", size: 10}, | |
{name: "left-forearm", size: 3}, | |
{name: "abdomen", size: 6}, | |
{name: "left-kidney", size: 1}, | |
{name: "left-hand", size: 2}, | |
{name: "left-knee", size: 2}, | |
{name: "left-thigh", size: 4}, | |
{name: "left-lower-leg", size: 3}, | |
{name: "left-achilles", size: 1}, | |
{name: "left-foot", size: 2}] | |
/** How would I probably solve this problem in ~Javascript~ ES6 */ | |
const regexLeft = /^left-/ | |
const matchingPart = part => { | |
const newName = part.name.replace(regexLeft, 'right-') | |
if (newName !== part.name) return { ...part, ...{ name: newName }} | |
} | |
const symmetrize = asymBodyParts => { | |
const finalBodyParts = new Set() | |
asymBodyParts.forEach(part => { | |
finalBodyParts.add(part) | |
finalBodyParts.add(matchingPart(part)) | |
}) | |
finalBodyParts.delete(undefined) // clean up | |
return finalBodyParts; | |
} | |
symmetrize(asymHobbitBodyParts) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** You need to add right body parts */ | |
const asymHobbitBodyParts = [{name: "head", size: 3}, | |
{name: "left-eye", size: 1}, | |
{name: "left-ear", size: 1}, | |
{name: "mouth", size: 1}, | |
{name: "nose", size: 1}, | |
{name: "neck", size: 2}, | |
{name: "left-shoulder", size: 3}, | |
{name: "left-upper-arm", size: 3}, | |
{name: "chest", size: 10}, | |
{name: "back", size: 10}, | |
{name: "left-forearm", size: 3}, | |
{name: "abdomen", size: 6}, | |
{name: "left-kidney", size: 1}, | |
{name: "left-hand", size: 2}, | |
{name: "left-knee", size: 2}, | |
{name: "left-thigh", size: 4}, | |
{name: "left-lower-leg", size: 3}, | |
{name: "left-achilles", size: 1}, | |
{name: "left-foot", size: 2}] | |
/** How would I probably solve this problem in ES7 & functional programming */ | |
// fp helpers | |
const compose3 = (f, g, v) => x => f(g(v(x))) | |
const curry = (fn) => { | |
const arity = fn.length; | |
return function $curry() { | |
var args = Array.from(arguments) | |
if (args.length < arity) { | |
return $curry.bind.apply($curry, [null].concat(args)) | |
} | |
return fn.apply(null, args) | |
} | |
} | |
const id = x => x | |
const newSet = array => { | |
return new Set(array) | |
} | |
// program | |
const replace = curry((what, withWhat, x) => x.replace(what, withWhat)) | |
const regexLeft = /^left-/ | |
function getMatchingPartName(partName) { | |
return replace(regexLeft, 'right-', partName) | |
} | |
const matchingPart = part => { | |
const newName = getMatchingPartName(part.name) | |
if (newName !== part.name) return { ...part, ...{ name: newName }} | |
else return part // same reference, Set will filter this out | |
} | |
function sortNonUnique(parts) { | |
return compose3(Array.from, newSet, id)(parts) | |
} | |
const symmetrize = asymBodyParts => { | |
let finalBodyParts = [] | |
asymBodyParts.forEach(part => { | |
finalBodyParts = [...finalBodyParts, ...sortNonUnique([part, matchingPart(part)])] | |
}) | |
return finalBodyParts; | |
} | |
symmetrize(asymHobbitBodyParts) |
OK, but now there's three times more code. And three times less JS programmers can read it. :(
Next Action:
Try partical application instead of currying. Create function replaceLeftWithRight
. Rm usage of id in sortNonUnique
.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Actually this solution in Clojure can be translated using
Array.from
.The problem now: es6 solution returns a Set, clojure one returns map (like an array).
So, you can do Array.from at the end, but you can also use immutable data structures* to make Set work and just do
finalBodyParts.push(Array.from(new Set([part, matchingPart(part)])))
(you can compose this)*- sadly Object.freeze will not work, but you can simply return the same reference from matchingPart
Next Action:
Apply my knowledge of composing stuff (damn, I've read Mostly Adequate Guide and bit of Functional-Light since then) and extract
part.name.replace(regexLeft, 'right-')
into separate function, return the samepart
frommatchingPart
, create a fn for using Set properly, replace es6 with es7 (Set is es7).