I have an object, of which parameters contain and array of object. I receive 1 object id and I need to find its position in that whole mess. With procedural programming I got it working with:
const opportunitiesById = {
1: [
{ id: 1, name: 'offer 1' },
{ id: 2, name: 'offer 1' }
],
2: [
{ id: 3, name: 'offer 1' },
{ id: 4, name: 'offer 1' }
],
3: [
{ id: 5, name: 'offer 1' },
{ id: 6, name: 'offer 1' }
]
};
const findObjectIdByOfferId = (offerId) => {
let opportunityId;
let offerPosition;
const opportunities = Object.keys(opportunitiesById);
opportunities.forEach(opportunity => {
const offers = opportunitiesById[opportunity];
offers.forEach((offer, index) => {
if (offer.id === offerId) {
opportunityId = Number(opportunity);
offerPosition = index;
}
})
});
return { offerPosition, opportunityId };
}
console.log(findObjectIdByOfferId(6)); // returns { offerPosition: 1, opportunityId: 3 }
However this is not pretty and I want to do that in a functional way.
I've looked into Ramda, and I can find an offer when I'm looking into a single array of offers, but I can't find a way to look through the entire object => each array to find the path to my offer.
R.findIndex(R.propEq('id', offerId))(opportunitiesById[1]);
The reason I need to know the path is because I then need tho modify that offer with new data and update it back where it is.
Thanks for any help
I would transform your object into pairs.
So for example transforming this:
{ 1: [{id:10}, {id:20}],
2: [{id:11}, {id:21}] }
into that:
[ [1, [{id:10}, {id:20}]],
[2, [{id:11}, {id:21}]] ]
Then you can iterate over that array and reduce each array of offers to the index of the offer you're looking for. Say you're looking for offer #21, the above array would become:
[ [1, -1],
[2, 1] ]
Then you return the first tuple which second element isn't equal to -1
:
[2, 1]
Here's how I'd suggest doing this:
const opportunitiesById = {
1: [ { id: 10, name: 'offer 1' },
{ id: 20, name: 'offer 2' } ],
2: [ { id: 11, name: 'offer 3' },
{ id: 21, name: 'offer 4' } ],
3: [ { id: 12, name: 'offer 5' },
{ id: 22, name: 'offer 6' } ]
};
const findOfferPath = (id, offers) =>
pipe(
toPairs,
transduce(
compose(
map(over(lensIndex(1), findIndex(propEq('id', id)))),
reject(pathEq([1], -1)),
take(1)),
concat,
[]))
(offers);
console.log(findOfferPath(21, opportunitiesById));
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.min.js"></script>
<script>const {pipe, transduce, compose, map, over, lensIndex, findIndex, propEq, reject, pathEq, take, concat, toPairs} = R;</script>
Then you can take that path to modify your offer as you see fit:
const opportunitiesById = {
1: [ { id: 10, name: 'offer 1' },
{ id: 20, name: 'offer 2' } ],
2: [ { id: 11, name: 'offer 3' },
{ id: 21, name: 'offer 4' } ],
3: [ { id: 12, name: 'offer 5' },
{ id: 22, name: 'offer 6' } ]
};
const updateOffer = (path, update, offers) =>
over(lensPath(path), assoc('name', update), offers);
console.log(updateOffer(["2", 1], '