简体   繁体   English

过滤具有多个 AND 组合属性对的对象数组

[英]Filter array of objects with multiple AND combination attribute pairs

My javascript array我的 javascript 阵列

const response = [
{
    "userId": "1",
    "questionId": "1",
    "answeredIndex": 1
},
{
    "userId": "1",
    "questionId": "2",
    "answeredIndex": 0
},
{
    "userId": "2",
    "questionId": "1",
    "answeredIndex": 1
},
{
    "userId": "2",
    "questionId": "2",
    "answeredIndex": 0
},
{
    "userId": "3",
    "questionId": "1",
    "answeredIndex": 0
},
{
    "userId": "3",
    "questionId": "2",
    "answeredIndex": 3
},
{
    "userId": "4",
    "questionId": "1",
    "answeredIndex": 1
},
{
    "userId": "4",
    "questionId": "2",
    "answeredIndex": 0
},
{
    "userId": "5",
    "questionId": "1",
    "answeredIndex": 0
},
{
    "userId": "5",
    "questionId": "2",
    "answeredIndex": 0
}]

I am looking for a solution which will return an array of userIds.我正在寻找一种将返回一组用户 ID 的解决方案。 Each user has answered two questions(questionId: 1 and questionId: 2).每个用户都回答了两个问题(questionId: 1 和 questionId: 2)。 I want the users who have answered both questions same.我希望回答这两个问题的用户相同。 So, I want to filter my array with an AND condition like below:所以,我想用 AND 条件过滤我的数组,如下所示:

if user selected answeredIndex: 1 for questionId: 1 AND if also the same user selected answeredIndex: 0 for questionId: 2 then, I want this user to be pushed in the result array.如果用户为 questionId: 1 选择了 answersIndex: 1 并且如果同一用户也为 questionId: 2 选择了 answersIndex: 0 那么,我希望这个用户被推送到结果数组中。

I tried below code but it is not working unfortunately.我尝试了下面的代码,但不幸的是它不起作用。

const targetUsers: string[] = [];
response.forEach((feedback) => {
  if ((feedback.questionId === '1' && feedback.answeredIndex === 1) ||
       feedback.questionId === '2' && feedback.answeredIndex === 0) {
    targetUsers.push(feedback.userId);
  }
});
console.log([...new Set(targetUsers)]);

My Expected output should be like below:我预期的 output 应该如下所示:

[
{
    "userId": "1",
    "questionId": "1",
    "answeredIndex": 1
},
{
    "userId": "1",
    "questionId": "2",
    "answeredIndex": 0
},
{
    "userId": "2",
    "questionId": "1",
    "answeredIndex": 1
},
{
    "userId": "2",
    "questionId": "2",
    "answeredIndex": 0
},
{
    "userId": "4",
    "questionId": "1",
    "answeredIndex": 1
},
{
    "userId": "4",
    "questionId": "2",
    "answeredIndex": 0
}]

So the combination of attribute pairs (questionId, answeredIndex) should be (1,1) AND (2,0) for each user, only then the user will be considered.因此,对于每个用户,属性对(questionId、answeredIndex)的组合应该是 (1,1) AND (2,0),然后才会考虑该用户。 Will highly appreciate if anyone helps me out here.如果有人在这里帮助我,将不胜感激。 Thanks in advance.提前致谢。

It's trick because the filter depends on multiple items in the array.这是技巧,因为过滤器依赖于数组中的多个项目。 The easier to undertand way to solve this is to keep the information of the previous answers we already iterated over:解决这个问题的更容易理解的方法是保留我们已经迭代过的先前答案的信息:

const response = [
{
    "userId": "1",
    "questionId": "1",
    "answeredIndex": 1
},
{
    "userId": "1",
    "questionId": "2",
    "answeredIndex": 0
},
{
    "userId": "2",
    "questionId": "1",
    "answeredIndex": 1
},
{
    "userId": "2",
    "questionId": "2",
    "answeredIndex": 0
},
{
    "userId": "3",
    "questionId": "1",
    "answeredIndex": 0
},
{
    "userId": "3",
    "questionId": "2",
    "answeredIndex": 3
},
{
    "userId": "4",
    "questionId": "1",
    "answeredIndex": 1
},
{
    "userId": "4",
    "questionId": "2",
    "answeredIndex": 0
},
{
    "userId": "5",
    "questionId": "1",
    "answeredIndex": 0
},
{
    "userId": "5",
    "questionId": "2",
    "answeredIndex": 0
}]


//object to make it easier to add mulitple questions
const rightQuestions = {
    "1": 1,
  "2": 0
}

//create a map to use as reference for each user
const usersToKeep = new Map()

response.forEach(item => {
    
  //if it's false, it has already an wrong answer
    if(usersToKeep.get(item.userId) === false) {
    return
  }
  
  // from here it either has not responded yet (undefined), or has a right answer (true)
  
    if(item.answeredIndex === rightQuestions[item.questionId]) {
    //the answer is valid
    usersToKeep.set(item.userId, true)
  } else {
        //the answer is not valid
    usersToKeep.set(item.userId, false)
  }
})

//now filter for the users we should keep
const results = response.filter(item => usersToKeep.get(item.userId))

//clear the map (not needed if the filter is inside a funcion)
usersToKeep.clear()


You could take a single loop approach for the answer off all users.您可以采用单循环方法来回答所有用户。 Then take only the ones who have all correct answered the questions.然后只选择所有正确回答问题的人。

This approach counts right answers and filter later by the needed count.这种方法计算正确答案并稍后按所需计数进行过滤。

 const response = [{ userId: "1", questionId: "1", answeredIndex: 1 }, { userId: "1", questionId: "2", answeredIndex: 0 }, { userId: "2", questionId: "1", answeredIndex: 1 }, { userId: "2", questionId: "2", answeredIndex: 0 }, { userId: "3", questionId: "1", answeredIndex: 0 }, { userId: "3", questionId: "2", answeredIndex: 3 }, { userId: "4", questionId: "1", answeredIndex: 1 }, { userId: "4", questionId: "2", answeredIndex: 0 }, { userId: "5", questionId: "1", answeredIndex: 0 }, { userId: "5", questionId: "2", answeredIndex: 0 }], answers = { 1: 1, 2: 0 }, temp = response.reduce((r, { userId, questionId, answeredIndex }) => { r[userId]??= 0; r[userId] += answers[questionId] === answeredIndex; return r; }, {}), targetUsers = Object.keys(temp).filter((count => k => temp[k] === count)(Object.keys(answers).length)); console.log(targetUsers);

Not sure if this is a goof idea or not but it might allow for complex filters:不确定这是否是一个愚蠢的想法,但它可能允许使用复杂的过滤器:

 const responses = [ { "userId": "1", "questionId": "1", "answeredIndex": 1 }, { "userId": "1", "questionId": "2", "answeredIndex": 0 }, { "userId": "2", "questionId": "1", "answeredIndex": 1 }, { "userId": "2", "questionId": "2", "answeredIndex": 0 }, { "userId": "3", "questionId": "1", "answeredIndex": 0 }, { "userId": "3", "questionId": "2", "answeredIndex": 3 }, { "userId": "4", "questionId": "1", "answeredIndex": 1 }, { "userId": "4", "questionId": "2", "answeredIndex": 0 }, { "userId": "5", "questionId": "1", "answeredIndex": 0 }, { "userId": "5", "questionId": "2", "answeredIndex": 0 } ]; // intersection from https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set function intersection(setA, setB) { let _intersection = new Set() for (let elem of setB) { if (setA.has(elem)) { _intersection.add(elem) } } return _intersection } const matchers = [ (item) => item.questionId === '1' && item.answeredIndex === 1, (item) => item.questionId === '2' && item.answeredIndex === 0, ]; const matching_users = matchers.map( (matcher) => responses.reduce( (acc, response) => matcher(response)? acc.add(response.userId): acc, new Set() ) ).reduce( (acc, set) => intersection(acc, set) ); const result = responses.filter((item) => matching_users.has(item.userId)); console.log(result);

To explain what it (hopefully) does:解释它(希望)的作用:

For each matcher it checks each response to see if it matches the condition, and if it does it adds it to a set containing the user ids.对于每个匹配器,它检查每个响应以查看它是否匹配条件,如果匹配,则将其添加到包含用户 ID 的集合中。 Then it finds the common elements of the user ids sets to find the user ids that matched all the matchers.然后它找到用户 id 集合的公共元素以找到匹配所有匹配器的用户 id。 Finally it filters the responses based on the list of user ids.最后,它根据用户 ID 列表过滤响应。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM