flimflam57
flimflam57

Reputation: 1334

Retrieve all the keys in an array of objects with a particular value

Given the object array:

var teachers = [ 
  {
    FullName: "Mark Jones",
    Address: "123 Main Street",
    Students: { 
      Monday: { 
        Stone: ["8:30", "10:30"],
        Cameron: [" ", " "],
        Julia: [" ", " "],
        Zoe: ["3:30", "5:30"]
      },
      Tuesday: {
        Jordan: ["12:00", "1:00"],
        Hal: [" ", " "],
        Kiko: [" ", " "]
      }
    }
  },
  {
     FullName: "Skip Roberts",
     Address: "123 Main Street",
     Students: { 
       Monday: { 
         Hal: ["9:30", "10:30"],
         Hana: [" ", " "],
         Ron: [" ", " "],
         Lola: ["4:30", "5:30"]
       },
       Tuesday: {
         Josh: ["11:00", "12:00"],
         George: [" ", " "],
         Paula: ["5:00", "6:00"]
       }
     }
   }
]

I'm wanting to retrieve all the keys (the student names) for all values equal to [" ", " "]. I tried the following but it only gives the first key and skips the rest (here I'm getting the keys for Monday:

var array = [];
teachers.forEach(function (doc) {
  array.push(_.findKey(doc.Students.Monday, [" ", " "]));
});
console.log(array);

This outputs:

["Cameron", "Hana"]

I'm wanting:

["Cameron", "Julia", "Hana", "Ron"]

Upvotes: 0

Views: 69

Answers (4)

Gruff Bunny
Gruff Bunny

Reputation: 27976

Here's a solution using underscore:

var result = _.chain(teachers)
    .pluck('Students')
    .map(day => _.pick(day.Monday, times => times[0] == ' ' && times[1] == ' '))
    .flatten()
    .map(_.keys)
    .flatten()
    .value()

Upvotes: 2

Titus
Titus

Reputation: 22474

The problem is that _.findKey retrieves only the first key and there doesn't seem to be any function for retrieve all of them. If you're not looking for an underscore solution you can do this in vanilla JavaScript using a function like this one:

var arr = [];

function lookForEmpty(obj){
    for(var k in obj){
        var v = obj[k];
        if(v instanceof Array){
            if(v.length == 2 && v[0] == " " && v[1] == " "){
                arr.push(k);
            }
        }else if(v instanceof Object){
            lookForEmpty(v);
        }
    } 
}

lookForEmpty(teachers);

Upvotes: 1

trincot
trincot

Reputation: 350167

Here are two native JavaScript (ES6) functions, one for a given day, and one for any day. They also make sure a name is listed only once:

function getStudentsForDay(teachers, day) {
    return [...teachers.reduce( (col, teacher) =>
        Object.keys(teacher.Students[day]).reduce(
            (col, name) => teacher.Students[day][name].every(time => time == ' ')
                           ? col.add(name) : col,
            col
        ), new Set() 
    )];
}

function getStudentsForAnyDay(teachers) {
    return [...teachers.reduce( (col, teacher) =>
        Object.keys(teacher.Students).reduce( (col, day) =>
            Object.keys(teacher.Students[day]).reduce(
                (col, name) => teacher.Students[day][name].every(time => time == ' ')
                               ? col.add(name) : col,
                col
            ), col
        ), new Set() 
    )];
}

var teachers = [ 
  {
    FullName: "Mark Jones",
    Address: "123 Main Street",
    Students: { 
      Monday: { 
        Stone: ["8:30", "10:30"],
        Cameron: [" ", " "],
        Julia: [" ", " "],
        Zoe: ["3:30", "5:30"]
      },
      Tuesday: {
        Jordan: ["12:00", "1:00"],
        Hal: [" ", " "],
        Kiko: [" ", " "]
      }
    }
  },
  {
     FullName: "Skip Roberts",
     Address: "123 Main Street",
     Students: { 
       Monday: { 
         Hal: ["9:30", "10:30"],
         Hana: [" ", " "],
         Ron: [" ", " "],
         Lola: ["4:30", "5:30"]
       },
       Tuesday: {
         Josh: ["11:00", "12:00"],
         George: [" ", " "],
         Paula: ["5:00", "6:00"]
       }
     }
   }
];

console.log('For Monday: ', getStudentsForDay(teachers, 'Monday'));
console.log('For any day: ', getStudentsForAnyDay(teachers));

Upvotes: 1

Arnauld
Arnauld

Reputation: 6110

Below is one possible way in vanilla JS, using the .reduce() and .filter() methods. You could use their underscore counterparts just as well.

var teachers = [{
    FullName: "Mark Jones",
    Address: "123 Main Street",
    Students: { 
      Monday : { Stone: ["8:30", "10:30"], Cameron: [" ", " "], Julia: [" ", " "], Zoe: ["3:30", "5:30"] },
      Tuesday: { Jordan: ["12:00", "1:00"], Hal: [" ", " "], Kiko: [" ", " "] }
    }
  }, {
     FullName: "Skip Roberts",
     Address: "123 Main Street",
     Students: { 
       Monday : { Hal: ["9:30", "10:30"], Hana: [" ", " "], Ron: [" ", " "], Lola: ["4:30", "5:30"] },
       Tuesday: { Josh: ["11:00", "12:00"], George: [" ", " "], Paula: ["5:00", "6:00"] }
     }
}];

function findStudents(day) {
  return teachers.reduce(function(res, cur) {
    var student = cur.Students[day];

    return res.concat(Object.keys(student).filter(function(k) {
      return (student[k][0] == " " && student[k][1] == " ");
    }));
  }, []);
}

var res = findStudents("Monday");
console.log(res);

Upvotes: 1

Related Questions