Redeclare variables defined in global scope with a loop - javascript

I am trying to redeclare variables defined in global scope. I'd like to wrap each function
const {values, map, each} = require('lodash')
const wrapFnInLog = (fn) => (...input) => {
console.log({name: fn.name, input})
const possiblePromise = fn.apply(null, input)
if (get(possiblePromise, 'then')) {
return possiblePromise.then(output => {
console.log({name: fn.name, output})
return output
})
} else {
console.log({name: fn.name, output: possiblePromise})
return possiblePromise
}
}
let a = (arr) => map(arr, i => i.name)
let b = (obj) => a(values(obj))
const provide = [a, b]
provide.forEach(fn => wrapFnInLog(fn))
const example = {
personTom: {
name: 'Tom'
},
personJerry: {
name: 'Jerry'
}
}
b(example)
I'd like the output to look like this:
{ name: 'b', input: [ { personTom: [Object], personJerry: [Object] } ] }
{ name: 'a', input: [ [ [Object], [Object] ] ] }
{ name: 'a', output: [ 'Tom', 'Jerry' ] }
{ name: 'b', output: [ 'Tom', 'Jerry' ] }
The only way I've been able to achieve this is without a loop and it's via deliberately overwriting each variable one by one.
a = wrapFnInLog(a)
b = wrapFnInLog(b)
I'm wondering if it's possible to loop over [a, b] and overwrite the function definition, while keeping them in global module scope.

as already commented, you can use a destructuring assignment to assign multiple variables at once
let a = (arr) => map(arr, i => i.name);
let b = (obj) => a(values(obj));
[a,b] = [a,b].map(wrapFnInLog);
but unlike a destructuring assignment in combination with a variable declaration (let [a,b] = ...) you have to be careful what you write before this assignment and that you properly seperate commands.
Because with automatic semicolon insertation or, JS not inserting a semicolon where one should be,
let a = (arr) => map(arr, i => i.name)
let b = (obj) => a(values(obj))
[a,b] = [a,b].map(wrapFnInLog)
will be interpreted as
let a = (arr) => map(arr, i => i.name);
let b = (obj) => {
return a(values(obj))[a,b] = [a,b].map(wrapFnInLog);
}
//or in other words
let b = (obj) => {
let tmp1 = a(values(obj));
a; //the `a,` in something[a,b];
let tmp2 = [a,b].map(wrapFnInLog);
tmp1[b] = tmp2;
return tmp2;
}

Related

How to get values from array of objects in javascript

I have an array of object from which I am trying to get values using map operator but I am getting the whole json objects all I want is just array of values.
Below is my code:
const obj = [
{
a: {
b: 'Paul',
}
},
{
c: 'Byeeee',
}
];
obj.map((val) => console.log(val));
what I am getting is
{ a: { b: 'Paul' } }
{ c: 'Byeeee' }
What I want is:
['Paul','Byeeee']
Someone let me know how can I get the desired output.
You can do this recursively. You can first start off by grabbing the values of your object, and then loop through those using .flatMap(). If you encounter a value that is an object, you can recursively grab the values of that object by recalling your function. Otherwise, you can return the value. The advantage of using .flatMap() here is that when the recursive call returns an array, we don't end up with inner arrays, but rather the array gets flattened into one resulting array:
const obj = [{ a: { b: 'Paul', } }, { c: 'Byeeee', } ];
const getValues = (obj) => {
return Object.values(obj).flatMap(val => Object(val) === val ? getValues(val) : val);
}
console.log(getValues(obj));
you can use the following solution.
const data = [{ a: { b: 'Paul' } }, { c: 'Byeeee' }];
const flatObjectValues = (obj, result) => {
// recursive function to get object values
const objValues = Object.values(obj);
if (objValues?.length > 0) {
objValues.map((v) => {
if (typeof v === 'object' && !Array.isArray(v)) {
flatObjectValues(v, result);
} else {
result.push(v);
}
return v;
});
}
};
const updatedData = [];
data.map((x) => flatObjectValues(x, updatedData));
console.log('updatedData: ', updatedData);
You can use recursion with array.reduce, like fellowing.
function getAllValues(objuct) {
return objuct.reduce((acc, curr) => {
if (typeof curr === 'object') {
return [...acc, ...getAllValues(Object.values(curr))];
}
return [...acc, curr];
}, []);
}
A recursive solution could be:
const arr = [{a: {b: "Paul",},},{c: "Byeeee",},];
const flatArrOfObjects = (arr) => {
const values = [];
for (const i in arr) flatObj(arr[i], values);
return values;
};
const flatObj = (obj, result) => {
for (const [key, value] of Object.entries(obj)) {
if (typeof value === "object") flatObj(value, result);
else result.push(value);
}
};
console.log(flatArrOfObjects(arr));

Javascript declarative/immutable version of 'maybe push'?

I have code like this:
A = [1,2,3]
if (condition) {A.push(4)}
A.push(5)
But my array is actually immutable so I can't do that. How can I do it all in one expression? I don't want a null value in the middle.
Here is one way:
A = [1, 2, 3, ...(condition ? [4] : []), 5]
If this is common in your codebase, and you want to keep undefined then you write a filter function with a sentinel.
const REMOVE = symbol('removeme')
const A = clean([1, 2, 3, condition ? 4 : REMOVE, 5])
function clean(arr) {return arr.filter(x=>x!==REMOVE)}
You can use the Writer monad here.
// type Writer t a = { value :: a, array :: [t] }
// pure :: a -> Writer t a
const pure = (value) => ({ value, array: [] });
// bind :: (Writer t a, a -> Writer t b) -> Writer t b
const bind = (writerA, arrow) => {
const writerB = arrow(writerA.value);
const array = [...writerA.array, ...writerB.array];
return { value: writerB.value, array };
};
// tell :: [t] -> Writer t ()
const tell = (array) => ({ value: undefined, array });
const writer = (gen) => {
const next = (data) => {
const { value, done } = gen.next(data);
return done ? value : bind(value, next);
};
return next(undefined);
};
const example = (condition) => writer(function* () {
yield tell([1, 2, 3]);
if (condition) yield tell([4]);
return tell([5]);
}());
console.log(example(true).array); // [1,2,3,4,5]
console.log(example(false).array); // [1,2,3,5]

Creates an object composed of the picked object properties: [duplicate]

This question already has answers here:
Filter object properties by key in ES6
(30 answers)
Closed 1 year ago.
I'm trying to create an object from object and list of properties.
const pick = (obj, ...fields) => {
return [...fields] = obj
};
How can I realise this?
Reduce the list of fields, and take the values from the original object:
const pick = (obj, ...fields) => fields.reduce((acc, field) => ({ ...acc, [field]: obj[field] }), {});
const obj = { a: 1, b: 2, c: 3 };
const result = pick(obj, 'a', 'c');
console.log(result);
You can use the in operator to ignore properties that don't exist on the original object:
const pick = (obj, ...fields) => fields.reduce((acc, field) => {
const value = obj[field];
if(field in obj) acc[field] = value;
return acc;
}, {});
const obj = { a: 1, b: 2, c: 3 };
const result = pick(obj, 'a', 'c', 'd');
console.log(result);
Try something like this:
const pick = (obj, ...fields) => Object.fromEntries(Object.entries(obj).filter(([k]) => fields.includes(k)))
Iterate through fields array and check if property is available in obj then put into final object which needs to be returned.
const pick = (obj, ...fields) => {
const finalObj = { };
for (field of fields) {
if (obj[field]) {
finalObj[field] = obj[field];
}
}
return finalObj;
};
const obj = { name: "test name", age: 25, title: "Mr.", city: "test city" };
console.log(pick(obj, "name", "age", "city", "other"));

Access javascript object value by array

I have an object like: const obj = { 'abc': {'def': 1 } } and I have an array like const arr = ['abc', 'def'] How can I access obj.abc.def property of my object with the array?
Obviously, obj[arr] doesn't work, also obj[arr.join('.') doesn't work.
What I want to do is:
const obj = { 'abc': {'def': 1 } }
const arr = ['abc', 'def']
const value = obj[arr] // crash
// value should contain 1
You could take a dynamic approach and reduce the keys and take a default object, if a part is not accessable.
const
getValue = (object, keys) => keys.reduce((o, k) => (o || {})[k], object),
obj = { abc: { def: 1 } },
arr = ['abc', 'def'],
value = getValue(obj, arr);
console.log(value);
console.log(getValue(obj, ['foo', 'bar']));
The base is
const obj = { 'abc': {'def': 1 } }
const arr = ['abc', 'def']
console.log(obj[arr[0]][arr[1]]);
or if you need to do it with a function...
const obj = { 'abc': {'def': 1 } }
const arr = ['abc', 'def']
function access(obj, arr) {
return arr.reduce((o, key) => o[key], obj);
}
console.log(access(obj, arr));
const obj = { 'abc': {'def': 1 } }
const arr = ['abc', 'def']
var value = obj;
for(let key of arr){
value = value[key];
}
console.log(value);
You can access the array property by index only. so arr[0] will work.
const obj = { 'abc': {'def': 1 } }
const arr = ['abc', 'def']
const value = obj[arr[0]][arr[1]]
console.log(value)
or you can run the loop over it.
const obj = { 'abc': {'def' : {'ghi': 1 } } };
const arr = ['abc', 'def', 'ghi'];
let ans = null;
for (let i=0; i<arr.length; i++) {
if(i==0) {
ans = obj[arr[0]];
}
else {
ans = ans[arr[i]];
}
}
console.log(ans)
You can use Array#reduce for a dynamic array.
const obj = { 'abc': {'def': 1 } }
const arr = ['abc', 'def']
const res = arr.reduce((o,prop)=>o[prop], obj);
console.log(res);
If you do not want errors to be thrown on properties that do not exist, you can use the optional chaining operator.
const obj = { 'abc': {'def': 1 } }
const arr = ['abc', 'def', 'notdefined', 'notdefined2']
const res = arr.reduce((o,prop)=>o?.[prop], obj);
console.log(res);
What you try to do is somewhat called object value "get by path", some library have support this and for example ramda is a production-ready library for that, you should not try to reinvent the wheel (practice is okay)
In your context, ramda's path method could help you achieve to the case of arbitrary array of properties
const obj = {
'abc': {
'def': 1,
'ghi': {
'jkl': 10
}
}
}
console.log(R.path(['abc', 'def'], obj))
console.log(R.path(['abc', 'ghi'], obj))
console.log(R.path(['abc', 'ghi', 'jkl'], obj))
console.log(R.path(['abc', 'ghi', 'jkl', 'mno'], obj))
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.25.0/ramda.min.js"></script>

Lodash findKey() method

As a part of a challenge I need to implement the .findKey() method myself. Below is the solution proposition, however, I get an error "predicate is not a function".
const _ = {
findKey(object, predicate) {
for (let key in object) {
let value = object[key];
let predicateReturnValue = predicate(value);
if (predicateReturnValue) {
return key;
};
};
undefined
return undefined;
}
};
Can anyone help?
function findKey(object, predicate) {
for (let key in object) {
let value = object[key];
let predicateReturnValue = predicate(value);
if (predicateReturnValue) { // just take the value
return key; // return key
}
}
}
const isEqual = a => b => a === b
const object = { a: 'Apple', b: 'Beer', c: 'Cake' }
alert(findKey(object, isEqual('Apple')));
alert(findKey(object, isEqual('Cakes')));

Categories

Resources