0

I have this array of objects which all have nested arrays, with each element having another array and with each of....you get the point. Deep nested arrays.

Let me explain what I am trying to achieve through an example. I have a list of groups. Each group has a list of heroes, each hero has a list of powers and each power has a list of strengths.

I want to be able to use the mat-stepper to iterate through each step selecting the group, then the hero, then the power and finally the strength. So when selecting a group from a mat-select, in the next step the mat-select will only hold the heroes belonging to that group and so on until the strength.

An example of what this group list could look like could be something like this:

[
  {
    "id": "g1",
    "group": "1",
    "heroes": [
      {
        "id": "g1h1",
        "hero": "hero1",
        "powers": [
          {
            "id": "g1h1p1",
            "power": "pyromancy",
            "strengths": [
              {
                "id": "g1h1p1s1",
                "strength": "undead"
              }
            ]
          },
          {
            "id": "g1h1p2",
            "power": "light",
            "strengths": [
              {
                "id": "g1h1p2s1",
                "strength": "shadow people"
              },
              {
                "id": "g1h1p2s2",
                "strength": "guidence"
              }
            ]
          }
        ]
      },
      {
        "id": "g1h2",
        "hero": "hero2",
        "powers": []
      }
    ]
  },
  {
    "id": "g2",
    "group": "2",
    "heroes": [
      {
        "id": "g2h1",
        "hero": "hero1",
        "powers": [
          {
            "id": "g2h1p1",
            "power": "electromancy",
            "strengths": [
              {
                "id": "g2h1p1s1",
                "strength": "metal armor"
              },
              {
                "id": "g2h1p1s2",
                "strength": "metal shields"
              }
            ]
          },
          {
            "id": "g2h1p2",
            "power": "invisibility",
            "strengths": []
          }
        ]
      }
    ]
  },
  {
    "id": "g3",
    "group": "group3",
    "heroes": []
  }
]

Each element within the lists all have their own unique id. Good news is I have this implemented and working. However I want to be able to filter the selection based on what has all ready been selected as well as only those powers with strengths.

So the removing requirements is as follows:

  • If strength has all ready been added to the list of selected strengths then remove it as a possible selection
  • If at any point an element has a empty list then remove it as a possible selection. So if a power has no strengths or hero has no powers then remove them.

So using the above example if my selected list all ready contains undead, shadow people and metal shields (id values, not the actual text) then the filtered list i am expecting back should be this:

[
  {
    "id": "g1",
    "group": "1",
    "heroes": [
      {
        "id": "g1h1",
        "hero": "hero1",
        "powers": [
          {
            "id": "g1h1p1",
            "power": "light",
            "strengths": [
              {
                "id": "g1h1p1s1",
                "strength": "guidence"
              }
            ]
          }
        ]
      }
    ]
  },
  {
  "id": "g2",
  "group": "2",
  "heroes": [
      {
        "id": "g2h1",
        "hero": "hero1",
        "powers": [
            {
              "id": "g2h1p1",
              "power": "electromancy",
              "strengths": [
                  {
                    "id": "g2h1p1s1",
                    "strength": "metal armor"
                  }
                ]
            }
          ]
      }
    ]
  }
]

I have tried many attempts but I'm just not getting back the right results. Below is one of my attempts. What am I doing wrong? Or is there a better way to do this?

  filterGroups()
  {
    //Iterate groups
    this.groups.forEach(group => {

      //remove empty groups
      if(group.heroes.length === 0)
      {
        let groupIndex: number = this.groups.findIndex(x => x.id === group.id);
        this.groups.splice(groupIndex, 1);
      }
      else {
        group.heroes.forEach(hero => {
          //remove heroes with no powers
          if(hero.powers.length === 0)
          {
            let heroIndex: number = group.heroes.findIndex(h => h.id === hero.id);
            group.heroes.splice(heroIndex, 1);
          }
          else {
            hero.powers.forEach(power => {
              //remove powers with no strengths
              if(power.strengths.length === 0)
              {
                let powerIndex: number = hero.powers.findIndex(p => p.id === power.id);
                hero.powers.splice(powerIndex,1);
              }            
              else {
                power.strengths.forEach(strength => {
                    if(this.selectedStrengths.some(x => x === strength.id))
                    {
                      let strengthIndex: number = power.strengths.findIndex(s => s.id === strength.id);
                      if(strengthIndex>-1)
                      {
                        power.strengths.splice(strengthIndex,1);
                      }
                    }              
                })

                //check if power is empty after filtering strengths
                if(power.strengths.length === 0)
                {
                  let powerIndex: number = hero.powers.findIndex(p => p.id === power.id);
                  hero.powers.splice(powerIndex,1);
                }
              }
            });

            //Check hero is empty after filtering powers
            if(hero.powers.length === 0)
            {
              let heroIndex: number = group.heroes.findIndex(h => h.id === hero.id);
              group.heroes.splice(heroIndex, 1);
            }
          }
        });

        //Check if group  is empty after filtering heroes
        if(group.heroes.length === 0)
        {
          let groupIndex: number = this.groups.findIndex(x => x.id === group.id);
          this.groups.splice(groupIndex, 1);
        }
      }
    });
  }
7
  • You are manipulating group.heroes (via .splice) inside of group.heroes.forEach, and that is probably part of the problem. Commented Dec 5, 2019 at 13:18
  • Hmm i see. Any idea on the right course of action for this type of filtering? Commented Dec 5, 2019 at 13:20
  • medium.com/poka-techblog/… - filter makes sense too Commented Dec 5, 2019 at 13:27
  • 1
    You have a typo on line 35 power.strengths.splice(stengthIndex,1); should be power.strengths.splice(strengthIndex,1); Commented Dec 5, 2019 at 13:29
  • Edited the question as it has nothing to typescript Commented Dec 5, 2019 at 13:36

1 Answer 1

2
    filterGroups() {
        return this.groups.filter(g => {
            g.heroes = g.heroes.filter(h => {
                h.powers = h.powers.filter(p => {
                    p.strengths = p.strengths.filter(s => this.selectedStrengths.indexOf(s.id) === -1);
                    return p.strengths.length > 0
                })
                return h.powers.length > 0;
            })
            return g.heroes.length > 0
        })
    }
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.