0

i have a script where i am trying to get the unique object based on state from the array of objects

The below scripts works fine, but I have one case where I have nested object in one kind of state has a sub-state, so I want to find the unique from the array of objects and get the unique.

The below snippet I am able to get the first level, but if we see the state => "EF" has a sub_state_details, so I need to get the unique from sub_state_details if state is EF

let inputArray = [{
    state: "AB",
  }, {
    state: "BC",
  }, {
    state: "BC",
  }, {
    state: "CD",
  }, {
    state: "CD",
  }, {
    state: "DE",
  }, {
    state: "EF",
    sub_state_details: {
      state: "EF-1"
    }
  }, {
    state: "EF",
    sub_state_details: {
      state: "EF-1"
    }
  },
  {
    state: "EF",
    sub_state_details: {
      state: "EF-2"
    }
  }
]

let resArr = []
inputArray.filter(function(item) {
  var i = resArr.findIndex(x => (x.state == item.state));
  if (i <= -1) {
    resArr.push({
      state: item.state
    });
  }
  return null;
});

console.log(resArr)

expected output

let output = [{
      state: "AB",
    }, {
      state: "BC",
    }, {
      state: "CD",
    }, {
      state: "DE",
    }, {
      state: "EF-1",
    },{
      state: "EF-2",
    }]

4 Answers 4

2

Other answers may give you the correct result, but they are using array functions incorrectly, granted they are based on your attempt. e.g. some using filter but never using the result from the filter. or trying to return null from a forEach even though forEach doesn't. return anything

reduce() is better suited to your case, as you are reducing one array to another, based on some conditions -

let inputArray = [{
    state: "AB",
  }, {
    state: "BC",
  }, {
    state: "BC",
  }, {
    state: "CD",
  }, {
    state: "CD",
  }, {
    state: "DE",
  }, {
    state: "EF",
    sub_state_details: {
      state: "EF-1"
    }
  }, {
    state: "EF",
    sub_state_details: {
      state: "EF-1"
    }
  },
  {
    state: "EF",
    sub_state_details: {
      state: "EF-2"
    }
  }
]

const result = inputArray.reduce((acc, cur) => {
  if(!acc.find((accItem) => accItem.state == cur.state)) {
    if(cur.state === 'EF') {
       if(cur.sub_state_details && !acc.find((accItem) => accItem.state === cur.sub_state_details.state)) {
          acc.push({state: cur.sub_state_details.state})
       }
    } else {
       acc.push({state: cur.state})
    }
    
  }
  return acc;
}, [])

console.log(result)

Sign up to request clarification or add additional context in comments.

4 Comments

you have added if(cur.state == 'EF') in the if condition, this is specific to 'EF' right, if state AB have substate. How it will behave?. We need to add one more condition in if statement
The question says - "The below snippet I am able to get the first level, but if we see the state => "EF" has a sub_state_details, so I need to get the unique from sub_state_details if state is EF"
But there are two EF-1s, only one is showing?
@Battledoosh look at the expected output in the OP, that's the expected behaviour
1

You can use a conditional statement to check if sub_state_details exists.

Like this:

let inputArray = [
  {
state: "AB",
  },
  {
state: "BC",
  },
  {
state: "BC",
  },
  {
state: "CD",
  },
  {
state: "CD",
  },
  {
state: "DE",
  },
  {
state: "EF",
sub_state_details: {
  state: "EF-1",
},
  },
  {
state: "EF",
sub_state_details: {
  state: "EF-1",
},
  },
  {
state: "EF",
sub_state_details: {
  state: "EF-2",
},
  },
];

let resArr = [];
inputArray.filter(function (item) {
  var i = resArr.findIndex((x) => x.state == item.state);
  if (i <= -1) {
if (item.sub_state_details) {
  resArr.push({
    state: item.sub_state_details.state,
  });
} else {
  resArr.push({
    state: item.state,
  });
}
  }
  return null;
});

console.log(resArr);

Comments

-1

This is actually a pretty simple solution. You first have to check if sub_state_details exists. If it does, we need to use that state instead. We can achieve this by using a variable called "sub," and if the sub_state_details object is defined, we use sub_state_details.state instead of item.state.

let inputArray = [{
    state: "AB",
  }, {
    state: "BC",
  }, {
    state: "BC",
  }, {
    state: "CD",
  }, {
    state: "CD",
  }, {
    state: "DE",
  }, {
    state: "EF",
    sub_state_details: {
      state: "EF-1"
    }
  }, {
    state: "EF",
    sub_state_details: {
      state: "EF-1"
    }
  },
  {
    state: "EF",
    sub_state_details: {
      state: "EF-2"
    }
  }
]

let resArr = []
inputArray.filter(function(item) {
  var i = resArr.findIndex(x => (x.state == item.state));
  let sub = item.sub_state_details;
  if(!sub) {sub=item}
  if (i <= -1) {
    resArr.push({
      state: sub.state
    });
  }
  return null;
});

console.log(resArr)

Hope I could help.

1 Comment

Gosh, I was just trying to help. What's the point of the -1?
-1

I have rewritten your code with some minor changes, that will solve your problem. Instead of checking only state, in the findIndex function, I have included one more condition for sub_state_details also if its present.

No need to worry about state & its sub-state, try code

var i = resArr.findIndex(x => 
  {
    return (x.state === item.state && ((x.sub_state_details && x.sub_state_details.state) ? x.sub_state_details.state === item.sub_state_details.state : true))
  });

Instead of directly pushing into the empty, check the array has sub-state details, push along with the array. Already we checked the state & substate are unique.

if(item.sub_state_details) {
      resArr.push({
        state: item.state,
        sub_state_details: item.sub_state_details
      });
    }

let inputArray = [{
    state: "AB",
  }, {
    state: "BC",
  }, {
    state: "BC",
  }, {
    state: "CD",
  }, {
    state: "CD",
  }, {
    state: "DE",
  }, {
    state: "EF",
    sub_state_details: {
      state: "EF-1"
    }
  }, {
    state: "EF",
    sub_state_details: {
      state: "EF-1"
    }
  },
  {
    state: "EF",
    sub_state_details: {
      state: "EF-2"
    }
  }
]

let resArr = []
inputArray.filter(function(item) {
  var i = resArr.findIndex(x => 
  {
    return (x.state === item.state && ((x.sub_state_details && x.sub_state_details.state) ? x.sub_state_details.state === item.sub_state_details.state : true))
  });
  if (i <= -1) {
    if(item.sub_state_details) {
      resArr.push({
        state: item.state,
        sub_state_details: item.sub_state_details
      });
    }
    else {
      resArr.push({
        state: item.state,
      });
    }
  }
  return null;
});

console.log(resArr);

I hope this would be useful.

2 Comments

your output does not match the expected output, and why are you using filter() when you dont do anything with the result from filter() ?
What makes this different then just straight up console.logging the entire object?

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.