export const findLast = new Function('arr', 'pred', ` for(let i = arr.length - 1; i >= 0; i--) { if(pred(arr[i])) { return arr[i] } } `) export const set_push = (x,y) => new Set([...x, y]) export const set_union = (x,y) => new Set([...x, ...y]) export const set_diff = (x,y) => { return new Set([...x].filter(el => !y.has(el))) } export const map_object = (obj, mapper) => Object.fromEntries( Object.entries(obj).map(([k, v]) => [k, mapper(k,v)]) ) export const filter_object = (obj, pred) => Object.fromEntries( Object.entries(obj).filter(([k, v]) => pred(k,v)) ) // https://bit.cloud/ramda/ramda/map-accum/~code export const map_accum = new Function('fn', 'acc', 'arr', ` let idx = 0; const len = arr.length; const result = []; let tuple = [acc]; while (idx < len) { tuple = fn(tuple[0], arr[idx], idx); result[idx] = tuple[1]; idx += 1; } return [tuple[0], result]; `) export const map_find = (arr, mapper) => arr.reduce( (result, curr, i) => result ?? mapper(curr, i), null ) export const pick_keys = (obj, keys) => { return Object.fromEntries( Object.entries(obj).filter(([k,v]) => keys.includes(k)) ) } export const stringify = val => JSON.stringify(val, null, 2) export const zip = (x,y) => { if(x.length != y.length){ throw new Error('zipped arrays must have same length') } else { return x.map((el, i) => [el, y[i]]) } } export const uniq = arr => [...new Set(arr)] // TODO remove /* function object_diff(a,b){ function do_object_diff(a,b, context=[]) { if(a == b){ return } if(a == null && b == null){ return } if(typeof(a) != 'object' || typeof(b) != 'object'){ throw new Error(`not an object ${a} ${b}`) } for(let key in a) { if(b[key] == null) { throw new Error(`missing ${key} in right object ${context.join('.')}`) } } for(let key in b) { if(a[key] == null) { throw new Error(`missing ${key} in left object ${context.join('.')}`) } do_object_diff(a[key], b[key], context.concat([key])) } } try { do_object_diff(a,b) } catch(e){ return e.message } } */