Skip to content

Instantly share code, notes, and snippets.

@3rdp
Last active June 26, 2019 08:44
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save 3rdp/7204a7dbb01da2abb77a34499c4e1964 to your computer and use it in GitHub Desktop.
Save 3rdp/7204a7dbb01da2abb77a34499c4e1964 to your computer and use it in GitHub Desktop.
Hitting hobbits for the first time
/** 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))
;; 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)])))))))
/** 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)
/** 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)
@3rdp
Copy link
Author

3rdp commented Jun 26, 2019

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 same part from matchingPart, create a fn for using Set properly, replace es6 with es7 (Set is es7).

@3rdp
Copy link
Author

3rdp commented Jun 26, 2019

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