Jason
Jason

Reputation: 396

How to filter an array inside of an array of objects?

I have this array that I want to check the days that has the job done inside.(In this case Monday)

const done = [
 {days:["Monday", "Tuesday", "Friday"] ,job: ["done", "not yet", "done"]},
 {days:["Monday", "Tuesday", "Friday"] ,job: ["done", "done", "done"]},
 {days:["Monday", "Tuesday", "Friday"] ,job: ["done", "not yet", "not yet"]},
]

 const freeTime = done
  .filter((event) => event.job === 'done')
console.log(freeTime) // I get nothing here?

Upvotes: 0

Views: 48

Answers (3)

Eric Leung
Eric Leung

Reputation: 2594

Here's a functional way of doing it. A bit convoluted, but it gets the job done.

const done = [
 {days:["Monday", "Tuesday", "Friday"] ,job: ["done", "not yet", "done"]},
 {days:["Monday", "Tuesday", "Friday"] ,job: ["done", "done", "done"]},
 {days:["Monday", "Tuesday", "Friday"] ,job: ["done", "not yet", "not yet"]},
]

// Keep days that occur done in all "weeks"
const numWeeks = done.length;

// Loop through all weeks and days to see when they are "done"
const daysObj = done.map((x) => x.job.map((x) => x == "done")
  .map((y, index) => y ? x.days[index] : ""))
  .map((x) => x.filter((day) => day))
  .reduce((acc, curr) => acc.concat(curr))
  .reduce(function(p, c){
    if (c in p) {
      p[c]++;
    } else {
      p[c]=1;
    }
    return p;
  }, {});
console.log(daysObj);
// {Monday: 3, Friday: 2, Tuesday: 1}

// Find days that occur done in all weeks
const result = Object.keys(daysObj)
  .map((x) => daysObj[x] == numWeeks ? x : null)
  .filter((x) => x)
console.log(result);
// ["Monday"]

Upvotes: 0

Mark
Mark

Reputation: 92440

To check which day has 'done' in all three objects you need to look at them all and build a map that will give you true or false for each day. You can do that like this:

const done = [
    {days:["Monday", "Tuesday", "Friday"] ,job: ["done", "not yet", "done"]},
    {days:["Monday", "Tuesday", "Friday"] ,job: ["done", "done", "done"]},
    {days:["Monday", "Tuesday", "Friday"] ,job: ["done", "not yet", "not yet"]},
   ]

var map = done.reduce((a, c ) => {
    c.days.forEach((day, i) => {
        a[day] =  ((a[day] == undefined || a[day] ) && c.job[i] === "done") || false
    })
    return a
}, {})

console.log(map)

This will result in on abject for true or false for each day. Is that what you'r after?

Upvotes: 1

Adrian
Adrian

Reputation: 8597

First of all, as I said in the comments, event.job is an Array so doing === 'done' will never evaluate to true.

What you need is to apply .every() filter on the array rather than ===.

const freeTime = done.filter((event) => event.job.every(isDone) )

function isDone(status){
  return status == "done";
}

This is of course assuming that all three values in jobs property must be 'done'.

JSFiddle

If your structure of those object is that each value in days corresponds to each value in jobs (i.e. index 0 in days is assigned to index 0 of jobs), then you need to design your objects more efficiently. The current design not efficient nor practical.

Upvotes: 0

Related Questions