2
\$\begingroup\$

Re-posting from StackOverflow as this is a place to review code that is already working.

I would like to know if there is a better way to deal with nested forEach when it comes to dealing with objects with properties that are nested arrays themselves.

My object (summarized):

{
 ...,
 "tx_responses": [
   {
     ...
     "logs" : [
       {
         ...,
         "events": [
             {
                 "type": "coin_received",
                 "attributes": [
                     {
                         "key": "receiver",
                         "value": "somesome"
                     },
                     {
                         "key": "amount",
                         "value": "somesome"
                     }
                 ]
             },
             ...
             {
                 "type": "transfer",
                 "attributes": [
                     {
                         "key": "recipient",
                         "value": "somesome"
                     },
                     {
                         "key": "sender",
                         "value": "somesome"
                     },
                     {
                         "key": "amount",
                         "value": "somesome"
                     }
                 ]
             },
             {
                 "type": "withdraw_rewards",
                 "attributes": [
                     {
                         "key": "amount",
                         "value": "somesomesomehere"
                     },
                     {
                         "key": "validator",
                         "value": "somesome"
                     }
                 ]
             },
             ...
         ]
     }
 ],
...

I am essentially trying to extract all { key: 'amount', value: 'somesomesomehere' } objects in the attributes array of the "type" : "withdraw_rewards" object in the events array.

Currently this is the code I wrote to carry out my task:

getWithdrawnAmounts: async(del_addr_) => {
    let withdrawnAmounts = [];
    const res = await axios.get("some_url_that_uses_del_addr_");
    res.data.tx_responses.forEach(txr => {
        txr.logs.forEach(log => {
            log.events.forEach(evnt => {
                if (evnt.type == "withdraw_rewards") {
                    evnt.attributes.forEach(attr => {
                        if (attr.key == "amount") {
                            withdrawnAmounts.push(attr);
                        }
                    })
                }
            })
        })
    });
    return withdrawnAmounts;
}

The code helps me to get what I need, but I was wondering if there is a better way to write my code so that I dont have to use so many nested .forEach methods. I was wondering if I should use .flat() or .flatMap() but I'm curious to know how would people approach this?

\$\endgroup\$
1
  • 1
    \$\begingroup\$ Welcome to Code Review! The current question title, which states your concerns about the code, is too general to be useful here. Please edit to the site standard, which is for the title to simply state the task accomplished by the code. Please see How to get the best value out of Code Review: Asking Questions for guidance on writing good question titles. \$\endgroup\$ Commented Sep 15, 2022 at 7:39

2 Answers 2

5
\$\begingroup\$

The pipeline can be written simpler:

  • replacing nested .forEach using .flatMap
  • replacing conditionals inside .forEach using .filter

Also, instead of appending to withdrawnAmounts in the deepest .forEach, you can make the pipeline return a filtered list.

return res.data.tx_responses
  .flatMap(txr => txr.logs)
  .flatMap(log => log.events)
  .filter(evnt => evnt.type === "withdraw_rewards")
  .flatMap(evnt => evnt.attributes)
  .filter(attr => attr.key === "amount");
\$\endgroup\$
0
\$\begingroup\$

here is example if you want to use flatmap.

It's an improvement of original as i am using only 3 flatmaps and forEach loop.

        const logs = data.tx_responses.flatMap(item=>item.logs);
            const events = logs.flatMap(item=>item.events)
            const attributes = events.flatMap(item=> { 
            if(item.type == "withdraw_rewards") {
return item.attributes
}
            else{
 return null
}
            })
attributes.forEach(attr => {
                    if (attr.key == "amount") {
                        withdrawnAmounts.push(attr);
                    }
                })
          
         
\$\endgroup\$
1
  • 4
    \$\begingroup\$ Welcome to Code Review! You have presented an alternative solution, but haven't reviewed the code. Please edit to show what aspects of the question code prompted you to write this version, and in what ways it's an improvement over the original. It may be worth (re-)reading How to Answer. \$\endgroup\$ Commented Sep 15, 2022 at 7:38

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.