const addressZip = person.get('addresses').filter((address) => address.get('legacy_id')).filter((newAddress) => (
getZIPErrors(newAddress.get('zip'))
))
when this function is executed it returns me as an
[array(0)] if it has no error
when it has an error it returns me as an [array(1)].
Instead of returning an array inside an array I just want to return a single array in this way if it has no error [] and if it has an error it should be like ['invalid']
You can implement a concatAll method within Array constructor, then use it to flatten your result:
Array.prototype.concatAll = function() {
return this.reduce((acc, curr) => acc = acc.concat(curr))
}
const addressZip = person
.get('addresses')
.filter(address => address.get('legacy_id'))
.filter(newAddress => getZIPErrors(newAddress.get('zip')))
.concatAll()
Related
I am trying to return a value that is situated within a matrix made up of arrays and nested arrays.
I am having trouble achieving this. My current approach is this:
//coords = 2,2,1,1,0
const addPrefix = (coords: []) => {
const completeCoords = (coords: []) => {
return coords.map((c) => {
return complex[c[0]][c[1]];
});
};
const values = completeCoords(coords);
console.log(values);
};
This current approach just returns this error:
Uncaught TypeError: Cannot read properties of undefined (reading 'undefined')
I want to loop through an array of objects to get a specific id and then render its data in a component in react, why it cannot be mapped, what is wrong here?
const projectData = projects.find(element => {
return element.id === projectId;
});
return (
{projectData.map(project => {
return <ProjectData key={project.id} {...project}></ProjectData>;
})}
)
find is returning either null or an object. you need an array to loop over the map. use the filter operator instead
const projectData = projects.filter(element => {
return element.id === projected;
});
The find() method returns the first element in the provided array that satisfies the provided testing function. If no values satisfy the testing function, undefined is returned.
So you don't need to use map for rendering.
const projectData = projects.find(element => {
return element.id === projectId;
});
return (
{projectData && <ProjectData key={projectData.id} {...projectData}></ProjectData>}
)
If there are many elements that satisfies the testing function please use the filter method, not find method.
In this case, the return value is the array, so you should use map for rendering.
const projectData = projects.filter(element => {
return element.id === projectId;
});
return (
{projectData.map(project => {
return <ProjectData key={project.id} {...project}></ProjectData>;
})}
)
I have this simple function that I am looking to simplify further:
setAreas() {
this.areas = ipcRenderer.sendSync('request', 'areas').map(_area => {
_area.locations = _area.locations.map(locationId => this.getLocation(locationId))
return _area
})
}
Is there any way to reduce this to a one-liner by performing the map on _area.locations and returning the updated _area?
One option would be to use Object.assign, which will return the base object being assigned to:
setAreas() {
this.areas = ipcRenderer.sendSync('request', 'areas').map(_area => (
Object.assign(_area, { locations: _area.locations.map(locationId => this.getLocation(locationId)) })
));
}
But that's not so readable. I prefer your current code.
Note that .map is appropriate for when you're transfoming one array into another. Here, you're only mutating every object in an existing array; forEach is more appropriate:
setAreas() {
this.areas = ipcRenderer.sendSync('request', 'areas');
this.areas.forEach((a) => a.locations = a.locations.map(locationId => this.getLocation(locationId)))
}
If getLocation only accepts one parameter, you can golf
a.locations = a.locations.map(locationId => this.getLocation(locationId))
down to
a.locations = a.locations.map(this.getLocation.bind(this))
(you could even remove the .bind(this) if this context isn't needed)
You can use destructuring
setAreas() {
this.areas = ipcRenderer.sendSync('request', 'areas').map(_area => ({
..._area, locations: _area.location.map(locationId => this.getLocation(locationId))
})
}
The assignement of a new property to each object in array, obtained with an async function in map is not working.
Here is my code:
asyncFunction.then(array => {
var promises = array.map(obj => {
return otherAsyncFunction(obj._id).then(prop => {
obj.url = prop;
return obj
})
})
Promise.all(promises).then(function (results) {
console.log(results)
})
res.send(user.friends)
})
The console.log(results) displays the same array.
I've tried to log the new obj juste before the return obj and it displays also the old obj
I've finally found the answer: the array was somehow not mutable, I just copied the initial array with the following:
let b = JSON.parse(JSON.stringify(array));
I'm wondering if there's a concise or specific way to access values in the middle of an FP chain in JavaScript. Example:
const somestuff = [true, true, false];
let filteredCount = 0;
somestuff.filter((val) => val)
.forEach((val) => console.log(val));
Above, I'd like to set filteredCount to the length of the array returned by the filter function. The most straight-forward way is:
const somestuff = [true, true, false];
const filteredStuff = somestuff.filter((val) => val);
let filteredCount = filteredStuff.length;
filteredStuff.forEach((val) => console.log(val));
This is certainly valid but it breaks our FP chain and introduces an additional holding variable. I'm wondering if there's a convention for accessing values in the middle of the chain. Something like .once() that runs once and implicitly returns the value passed in, but nothing like that exists.
For debugging, I often use a function called tap to temporarily add a side-effect (like your console.log) to a function:
const tap = f => x => (f(x), x);
This function returns whatever it is passed, but not before calling another function with the value. For example:
const tap = f => x => (f(x), x);
const tapLog = tap(console.log);
const x = tapLog(10);
console.log("x is", x);
Your snippet basically does this:
Filter a list
(log the list)
Retrieve a length property from an array
If you construct this function using pipe or compose, you can "inject" the console.log in between without interrupting the data flow:
const countTrues = pipe(
filter(isTrue),
prop("length")
);
const countTruesWithLog = pipe(
filter(isTrue),
tap(console.log),
prop("length")
);
In a snippet:
// Utils
const isTrue = x => x === true;
const prop = k => obj => obj[k];
const tap = f => x => (f(x), x);
const filter = f => xs => xs.filter(f);
const pipe = (...fns) => x => fns.reduce((res, f) => f(res), x);
// Logic:
// Filter an array using the isTrue function
// and return the length of the result
const countTrues = pipe(
filter(isTrue),
prop("length")
);
// Create a filter with a console.log side-effect
// and return the length of the result
const countTruesWithLog = pipe(
filter(isTrue),
tap(console.log),
prop("length")
);
// App:
const somestuff = [true, true, false];
console.log("pure:");
const countA = countTrues(somestuff)
console.log(countA);
console.log("with log:")
const countB = countTruesWithLog(somestuff);
console.log(countB);
The reason there's no Array.prototype method like that, is that it has a side effect. This is something that is specifically avoided in functional programming.
However if you don't care about writing 'Pure Functions', or even the functional paradigm, you could put the side effect in your callbacks, or write a function in the Array prototype.
ie.
Array.prototype.once = function(callback) {
callback(this)
return this
}
You also have other hacky options like in the other answer
I don't think there's something like that by default. What you can do is extend Array, but I'm not really fond of extending framework classes (clashes with other once implementations for example). In this case you'd end up with:
Array.prototype.once = function once(func) {
func(this);
return this;
}
which is called like:
var filteredStuff = somestuff
.filter((val) => val)
.once(function(array) {
console.log(array.length);
})
.forEach((val) => console.log(val));
On the other hand, you can try to use default functions. One of these function that can access all items at once is reduce. Define a function once, that will call its first parameter once (:)) and you'd end up with something like:
function once(func) {
return function(accumulator, currentValue, currentIndex, array) {
if(currentIndex === 1) {
func(array);
}
return array;
}
}
which you'd be able to call like this:
var filteredStuff = somestuff
.filter((val) => val)
.reduce(once(function(array) {
console.log(array.length);
}), [0])
.forEach((val) => console.log(val));
Notice the ugly [0] to ensure once calls the passed function at least once (empty array included).
Both solutions aren't too neat, but it's the best I can come up with given the criteria.