Skip to content

Instantly share code, notes, and snippets.

@Mandorlo
Last active March 26, 2020 10:09
Show Gist options
  • Save Mandorlo/2e07ba71000382f477a4cad004a050f8 to your computer and use it in GitHub Desktop.
Save Mandorlo/2e07ba71000382f477a4cad004a050f8 to your computer and use it in GitHub Desktop.
/* ======================================================= */
/* OPS SUR LES ENSEMBLES */
/* ======================================================= */
function xor(arr1, arr2, fn = null) {
let arr = []
let xor1 = identity(arr1)
let xor2 = identity(arr2)
if (fn && typeof fn == 'string') {
xor1 = arr1.map(el => el[fn])
xor2 = arr2.map(el => el[fn])
} else if (fn) {
xor1 = arr1.map(fn)
xor2 = arr2.map(fn)
}
for (let i = 0; i < arr1.length; i++) {
if (xor2.indexOf(xor1[i]) < 0) arr.push(arr1[i])
}
for (let i = 0; i < arr2.length; i++) {
if (xor1.indexOf(xor2[i]) < 0) arr.push(arr2[i])
}
return arr
}
// renvoie l'array intersection de @arr1 et @arr2
function intersection(arr1, arr2) {
let res = []
for (let o of arr1) {
if (arr2.indexOf(o) > -1) res.push(o)
}
return res
}
// renvoie la différence (au sens d'ensembles) o2 - o1
// càd renvoie un objet avec les paires key/val de o2 qui ne sont pas dans o1
// si strict = true on compare key et val, sinon on ne compare que la présence de key dans o1
function objDiff(o2, o1, strict = true) {
let o = {}
for (let attr in o2) {
if (o1[attr] != o2[attr] || (!strict && !o1.hasOwnProperty(attr))) {
o[attr] = o2[attr]
}
}
return o
}
/**
* Returns the element in o at the corresponding path
* e.g.
* - o = {a:1, b: {c:2, d:3} }
* - path = "/b/c"
* getPath(o, path) --> 2
*
* @param object o this is a javascript object
* @param string|array path describes a path in the object o
* @param optional string sep is the path separator
* @param optional any retval is the value to return if path is not found in o
*
* @return any : returns the sub-object in o at the right path if it exists
* @return any : returns retval if path cannot be found in o
*
*/
function getPath(o, path, sep = '/', retval = false) {
if (typeof path === 'string') {
if (!path.length) return o;
// here below we remove sep characters at the beginning and end of path string
// and we deduplicate consecutive sep characters
path = path.replace(new RegExp(`^\\${sep}+|\\${sep}+$`, "g"), '').replace(new RegExp(`\\${sep}+`, "g"), sep);
path = path.split(sep);
}
if (path.length == 0) return o;
return (path[0] in o) ? getPath(o[path[0]], path.slice(1), sep, retval) : retval;
}
function uniq(arr) {
let unique = []
for (let el of arr) {
if (unique.indexOf(el) < 0) unique.push(el)
}
return unique
}
/**
* Returns only unique values of loo
* if attr != null returns only unique values comparing elements based on attribute attr
*
* @param array of objects loo a list of elements (usually objects but not mandatory)
* @param string attr the attribute to check unicity. if attr == null, checks elements of loo directly
*
* @return loo with only unique elements in terms of o[attr]
*/
function uniqBy(loo, attr = null) {
let mem = [];
if (!attr) return loo.filter(el => {
if (mem.includes(el)) return false;
mem.push(el); return true;
});
return loo.filter(el => {
if (mem.includes(el[attr])) return false;
mem.push(el[attr]); return true;
})
}
Array.prototype.sortBy = function(fn) {
if (typeof fn == 'string') fn = (el) => el[fn];
return this.sort((a,b) => {
if (fn(a) < fn(b)) return -1;
return 1
})
}
Array.prototype.splitBy = function(fn) {
let ids = []
let res = []
for (let i = 0; i < this.length; i++) {
let id = fn(this[i])
let n = ids.indexOf(id)
if (n > -1) {
res[n].push(this[i])
} else {
ids.push(id)
res.push([this[i]])
}
}
return res
}
function identity(arr) {
if (!arr || typeof arr.map != 'function') return arr;
return arr.map(el => el)
}
// arr est un array d'objet.
// mapAttr renvoie un nouvel array des mêmes objets mais avec l'attribut attr mis à jour avec fn(el)
function mapAttr(arr, attr, fn) {
return arr.map(el => {
el[attr] = fn(el)
return el
})
}
/* ======================================================= */
/* MATH */
/* ======================================================= */
Array.prototype.sum = function() {
return this.reduce((a,b) => a+b, 0)
}
Array.prototype.mean = function() {
if (this.length == 0) return 0;
return this.reduce((a,b) => a+b, 0) / this.length
}
Array.prototype.square = function() {
return this.map(el => Math.pow(el, 2))
}
Array.prototype.variance = function() {
return this.square().mean() - Math.pow(this.mean(), 2)
}
/* ======================================================= */
/* OBJECTS MANIPULATIONS */
/* ======================================================= */
// traverse un objet profondément et dès que @condition(attr, val, tree) est vérifiée, on renvoie result(attr, val, tree)
export function traverse(obj, condition, result, tree = {}) {
let debug = false
let new_obj = {}
if (debug) console.log("traversing OBJ : ", obj)
if (typeof obj == 'object' && !obj.length) {
if (debug) console.log("OBJ ok")
for (let attr in obj) {
if (condition(attr, obj[attr], tree)) {
new_obj[attr] = result(attr, obj[attr], tree)
if (debug) console.log("condition passed for " + attr, new_obj[attr], tree)
} else {
if (debug) console.log("going to traverse one level deeper on " + attr)
new_obj[attr] = traverse(obj[attr], condition, result, {val: attr, parent: tree})
}
}
return new_obj
} else if (condition(null, obj, tree)) {
if (debug) console.log('not obj but condition true. Returning : ', result(null, obj, tree))
return result(null, obj, tree)
} else {
if (debug) console.log('not obj. Returning : ', obj)
return obj
}
}
/* ======================================================= */
/* CONVERSIONS */
/* ======================================================= */
// joinObj({a:1,b:2}, '&', '=') = "a=1&b=2"
function joinObj(o, sep_attr = '&', sep_val = '=') {
let arr = []
for (let attr in o) {
arr.push(attr + sep_val + o[attr])
}
return arr.join(sep_attr)
}
function obj2arr(o, add_key = '') {
let arr = []
for (let attr in o) {
if (add_key != '') o[attr][add_key] = attr;
arr.push(o[attr])
}
return arr
}
// renvoie un objet à partir d'un array
function map2Obj(arr, fn_id, fn_val) {
let o = {}
for (let i = 0; i < arr.length; i++) {
let key;
if (typeof fn_id == 'string') key = arr[i][fn_id];
else key = fn_id(arr[i]);
let val;
if (typeof fn_val == 'string') val = arr[i][fn_val];
else val = fn_val(arr[i])
o[key] = val
}
return o
}
/**
* Checks if a string is a valid email
*/
function checkEmail(s) {
return /^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$/.test(s);
}
function normalize(s) {
return s.normalize("NFD").replace(/[\u0300-\u036f]/g, "").toLowerCase().replace(/[^a-z0-9\-\_]/g, "")
}
function basename(path) {
return path.split('/').reverse()[0];
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment