1

I am generating a dynamic array like below. What I wanted to achieve is to compare the first set with the second and return the common items based on id into a new array. Also the pending and required value should be grater than 0.

For example, Case : 1

let arr = [
  {
    0: { id: 1, name: "A", required: 1, pending: 1 },
    1: { id: 2, name: "B", required: 0, pending: 0 }
  },
  {
    0: { id: 1, name: "A", required: 1, pending: 1 },
    1: { id: 2, name: "B", required: 1, pending: 1 },
    2: { id: 3, name: "C", required: 0, pending: 0 }
  }
]

The result would be A in this case as follows.

[
{ id: 1, name: "A", required: 1, pending: 1 }
]

Another case, Case : 2 since the array is dynamically generated. So the following can be possible.

let arr = [
      {
        0: { id: 1, name: "A", required: 1, pending: 1 },
        1: { id: 2, name: "B", required: 1, pending: 1 },
        2: { id: 3, name: "C", required: 0, pending: 0 }
      }
    ]

The expected output of this would be

  [
    { id: 1, name: "A", required: 1, pending: 1 },
    { id: 2, name: "B", required: 1, pending: 1 }
  ]

The below function gives the desired output for Case 1. This function not works for Case 2. Can anybody help me to solve this?

let test = arr .reduce((p, c) => p.filter(e =>c.some(s => s.id === e.id && s.pending> 0 && e.pending> 0 && s.required> 0 && e.required> 0)));
6
  • what is your expected output? Commented Jul 29, 2020 at 14:00
  • 1
    The syntax of your input array is incorrect. { { ... }, { ... } } is not valid, did you mean [ { ... }, { ... } ]? Commented Jul 29, 2020 at 14:00
  • I would like to return the elements whose pending and required value >0 and otherwise it should return empty array Commented Jul 29, 2020 at 14:06
  • Yeah, sure, but the input array is not valid syntax in javascript. Is it an array of array of objects? Commented Jul 29, 2020 at 14:07
  • @ibrahimmahrir I have corrected the array format Commented Jul 29, 2020 at 14:22

4 Answers 4

1

Can you try this? It's worked for me..

let test = arr.reduce((p, c) => p.filter(e =>c.some(s => s.id === e.id && s.pending> 0 && e.pending> 0 && s.required> 0 && e.required> 0)));

let res = arr.length>1?test:(test.filter(s =>  s.pending> 0 && s.required> 0));
Sign up to request clarification or add additional context in comments.

Comments

1

You could use map and use Object.values to get the values of the nested objects and an object to deduplicate

var arr=[{
  0:{id: 1, name: "A", required: 1, pending: 1},
  1:{id: 2, name: "B", required: 0, pending: 0}
  },
  {
  0:{id: 1, name: "A", required: 1, pending: 1},
  1:{id: 2, name: "B", required: 1, pending: 1},
  2:{id: 3, name: "C", required: 0, pending: 0}
  }
  ]


  map1=new Map()
  map2=new Map()

  var res = arr.map(o => Object.values(o).forEach(
  s => { if(s.required > 0 && s.pending > 0 && !map2.get(s.name)) 
          map1.set(s.name,s)
         else map2.set(s.name,s)
  }))
  console.log([...map1.values()])

let arr = [
  {
    0: { id: 1, name: "A", required: 1, pending: 1 },
    1: { id: 2, name: "B", required: 1, pending: 1 },
    2: { id: 3, name: "C", required: 0, pending: 0 }
  }
]


  map1=new Map()
  map2=new Map()

  var res = arr.map(o => Object.values(o).forEach(
  s => (s.required > 0 && s.pending > 0 && !map2.get(s.name)) ? map1.set(s.name,s) :  map2.set(s.name,s)
))
  console.log([...map1.values()])

5 Comments

This works, I don't want to repeat the id 1 in the result. Expected to get id 1 and 2 in the result array
I would not flat-map this data, because there are entries with duplicate IDs.
@ Jomol MJ I have fixed it now check it out
@Sven.hig One more thing, in the first set of array, B's pending and required is 0 and in the next set it is 1. So in this case is it possible to exclude B and only return A?
@Sven.hig I have updated the question can you please look into it?
0

Besides your psudo-matrix code, you can create a simple filter predicate function that takes an entry and short-circuits if any of the conditions fail. You need to check for violating condition instead of requested conditions.

Just return true at the very end.

As for your data, since you have an array of objects (which themselves contain objects), you will need to map each group to a reduction so that you can filter-out the key-value pairs where the value (entry) does not meet the criteria of the predicate. Reducing is just mapping and filtering all at once. You need to reduce, because you cannot filter an object by keys.

const data = [{
  0: { id: 1, name: "A", required: 1, pending: 1 },
  1: { id: 2, name: "B", required: 0, pending: 0 }
}, {
  0: { id: 1, name: "A", required: 1, pending: 1 },
  1: { id: 2, name: "B", required: 1, pending: 1 },
  2: { id: 3, name: "C", required: 0, pending: 0 }
}]

const isRequiredAndPendingGreaterThanZero = (entry) => {
  if (entry == null) return false;
  if (entry.required !== 1) return false;
  if (entry.pending < 1) return false;
  return true;
}

console.log(data.map(group => {
  return Object.entries(group).reduce((res, entry) => {
    let [ key, value ] = entry;
    return isRequiredAndPendingGreaterThanZero(value)
      ? { ...res, [key]: value } : res;
  }, {});
}));
.as-console-wrapper { top: 0; max-height: 100% !important; }

Here is a more dynamic version that checks for EVERY valid condition and allows you to define conditions for each key.

This example uses a simplified data structure of an array of objects, but it can easily be adapted to work for any list data structure, grouped or not.

const data = [
  { id: 1, name: "A", required: 1, pending: 1 },
  { id: 2, name: "B", required: 1, pending: 1 },
  { id: 3, name: "C", required: 0, pending: 0 }
];

const isValid = (entry, criteria) => {
  if (entry == null) return false;
  return Object.keys(criteria).every(key => criteria[key](entry[key]));
}

console.log(data.filter(entry => isValid(entry, {
  required : v => v === 1,
  pending  : v => v > 0
})));
.as-console-wrapper { top: 0; max-height: 100% !important; }

3 Comments

too complicated for such a simple task
@Sven.hig not complicated at all… The first part is a straight solution. How is a simple predicate too complicated?
@Mr.Polywhirl Can you please look into the updated question and help me?
0

Use forEach and push to result array.

const filter = (arr) => {
  const res = [];
  const track = {};
  arr.forEach((obj) =>
    Object.entries(obj).forEach(([i, item]) => {
      const isValid = ["required", "pending"].every((key) => item[key] > 0);
      if (isValid && !(item.name in track)) {
        res.push({ [i]: item });
      }
      track[item.name] = isValid;
    })
  );
  return res;
};

let arr1 = [
  {
    0: { id: 1, name: "A", required: 1, pending: 1 },
    1: { id: 2, name: "B", required: 0, pending: 0 },
  },
  {
    0: { id: 1, name: "A", required: 1, pending: 1 },
    1: { id: 2, name: "B", required: 1, pending: 1 },
    2: { id: 3, name: "C", required: 0, pending: 0 },
  },
];

let arr2 = [
      {
        0: { id: 1, name: "A", required: 1, pending: 1 },
        1: { id: 2, name: "B", required: 1, pending: 1 },
        2: { id: 3, name: "C", required: 0, pending: 0 }
      }
    ]
    
console.log(filter(arr1));
console.log('------------');
console.log(filter(arr2));

Update: Output without indexes.

const filter = (arr) => {
  const res = [];
  const track = {};
  arr.forEach((obj) =>
    Object.entries(obj).forEach(([i, item]) => {
      const isValid = ["required", "pending"].every((key) => item[key] > 0);
      if (isValid && !(item.name in track)) {
        // res.push({ [i]: item });
        res.push(item);
      }
      track[item.name] = isValid;
    })
  );
  return res;
};

let arr1 = [
  {
    0: { id: 1, name: "A", required: 1, pending: 1 },
    1: { id: 2, name: "B", required: 0, pending: 0 },
  },
  {
    0: { id: 1, name: "A", required: 1, pending: 1 },
    1: { id: 2, name: "B", required: 1, pending: 1 },
    2: { id: 3, name: "C", required: 0, pending: 0 },
  },
];

let arr2 = [
      {
        0: { id: 1, name: "A", required: 1, pending: 1 },
        1: { id: 2, name: "B", required: 1, pending: 1 },
        2: { id: 3, name: "C", required: 0, pending: 0 }
      }
    ]
    
console.log(filter(arr1));
console.log('------------');
console.log(filter(arr2));

6 Comments

Is it possible to remove the repeated item and also in the first set of array, B's pending and required is 0 and in the next set it is 1. So in this case is it possible to exclude B and only return A?
@JomolMJ, Updated the answer to maintain a set to avoid duplicates. Hope that helps. If didn't understand correctly, Can you update it with expected output?
[ { "0": { "id": 1, "name": "A", "required": 1, "pending": 1 } }, ] - this is expected
@JomolMJ, Ah got it. My bad, Actually question you already mentioned expected output. Here is updated version which handles the scenarios mentioned. :)
can you look at the updated question and help me to solve this?
|

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.