检索具有特定值的对象数组中的所有键

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

给定对象数组:

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"]
       }
     }
   }
]

我想要检索等于 [" ", " "] 的所有值的所有键(学生姓名)。我尝试了以下但它只提供了第一个密钥并跳过了其余部分(这里我正在获取星期一的密钥:

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

这输出:

["Cameron", "Hana"]

我想要:

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

下面是 vanilla JS 中的一种可能方式,使用 .reduce().filter() 方法。你也可以使用他们的下划线对应物。

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);

这里有两个原生 JavaScript (ES6) 函数,一个用于给定的一天,一个用于任意一天。他们还确保名称只列出一次:

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));

问题是 _.findKey 只检索第一个键,似乎没有检索所有键的函数。 如果你不是在寻找下划线解决方案,你可以使用像这样的函数在 vanilla JavaScript 中做到这一点:

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);

下面是一个使用下划线的解决方案:

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