【问题标题】:Nested array mapping and filtering in javascriptjavascript中的嵌套数组映射和过滤
【发布时间】:2022-01-13 11:16:24
【问题描述】:

我正在设计一个系统,但我遇到了一些瓶颈。

我有这样的用户数组:

 const users = [
  {
    name: "Jack",
    workspaces: [
      {
        _id: "61216512315615645jbk",
        permissions: ["CAN_DELETE_WORKSPACE", "CAN_EDIT_PROJECT"],
      },
      {
        _id: "41ss16512315615645bk",
        permissions: ["CAN_DELETE_WORKSPACE", "CAN_EDIT_PROJECT"],
      },
    ],
  },
  {
    name: "Joe",
    workspaces: [
      {
        _id: "71216512315615645jbk",
        permissions: ["CAN_DELETE_WORKSPACE"],
      },
    ],
  },
];

我有这样的 activeWorkspace 对象:

const activeWorkspace = {
  name: "W1",
  _id: "61216512315615645jbk",
};

我需要过滤users数组中workspace_id等于activeWorkspace_id的对象。

输出必须是这样的:

{
    name: "Jack",
    workspaces: [
      {
        _id: "61216512315615645jbk",
        permissions: ["CAN_DELETE_WORKSPACE", "CAN_EDIT_PROJECT"],
      },
      {
        _id: "41ss16512315615645bk",
        permissions: ["CAN_DELETE_WORKSPACE", "CAN_EDIT_PROJECT"],
      },
    ],
}

我该怎么做?

此外: 如果我们想返回一个数组,而不是一个对象,我们应该怎么做呢?像这样:

[{
        name: "Jack",
        workspaces: [
          {
            _id: "61216512315615645jbk",
            permissions: ["CAN_DELETE_WORKSPACE", "CAN_EDIT_PROJECT"],
          },
          {
            _id: "41ss16512315615645bk",
            permissions: ["CAN_DELETE_WORKSPACE", "CAN_EDIT_PROJECT"],
          },
        ],
}]

谢谢

【问题讨论】:

  • 预期的结果应该是什么?请添加问题本身
  • filter() 和 some() 是你需要使用的。
  • activeWorkspace._id61216512315615645jbk 但在预期输出中你有 41ss16512315615645bk
  • 为什么不包括 Joe?这是拼写错误/复制粘贴错误吗?
  • JackJoe 都有 61216512315615645jbk 工作区 _id

标签: javascript node.js arrays


【解决方案1】:

如果只有一个匹配项。您需要使用 find()。在 find 方法中,您想使用 some() 来查找 _id 匹配项。

 const users = [
  {
    name: "Jack",
    workspaces: [
      {
        _id: "61216512315615645jbk",
        permissions: ["CAN_DELETE_WORKSPACE", "CAN_EDIT_PROJECT"],
      },
      {
        _id: "41ss16512315615645bk",
        permissions: ["CAN_DELETE_WORKSPACE", "CAN_EDIT_PROJECT"],
      },
    ],
  },
  {
    name: "Joe",
    workspaces: [
      {
        _id: "CHANGED_ID",
        permissions: ["CAN_DELETE_WORKSPACE"],
      },
    ],
  },
];

const activeWorkspace = {
  name: "W1",
  _id: "61216512315615645jbk",
};

const active = users.find(function (user) {
  return user.workspaces.some( function (workspace) {
    return workspace._id === activeWorkspace._id;
  });
});

console.log(active);


// Same thing as above, just done with a modern approach
const active2 = users.find(({workspaces}) => workspaces.some(({_id}) => _id === activeWorkspace._id));

console.log(active2);

现在,如果可能有多个匹配项(您在拼写错误之前的原始代码,您将使用 filter() 和 some() 来查找在其数组中具有工作区的所有用户。

 const users = [
  {
    name: "Jack",
    workspaces: [
      {
        _id: "61216512315615645jbk",
        permissions: ["CAN_DELETE_WORKSPACE", "CAN_EDIT_PROJECT"],
      },
      {
        _id: "41ss16512315615645bk",
        permissions: ["CAN_DELETE_WORKSPACE", "CAN_EDIT_PROJECT"],
      },
    ],
  },
  {
    name: "Joe",
    workspaces: [
      {
        _id: "61216512315615645jbk",
        permissions: ["CAN_DELETE_WORKSPACE"],
      },
    ],
  },
];

const activeWorkspace = {
  name: "W1",
  _id: "61216512315615645jbk",
};

const active = users.filter(function (user) {
  return user.workspaces.some( function (workspace) {
    return workspace._id === activeWorkspace._id;
  });
});

console.log(active);


// Same thing as above, just done with a modern approach
const active2 = users.filter(({workspaces}) => workspaces.some(({_id}) => _id === activeWorkspace._id));

console.log(active2);

【讨论】:

  • @RandyCasburn 第二个例子处理这个案例。
  • 必须承认,您的答案更简洁,做得很好,为什么 active2 不再是现代方法了?
  • 啊……哈哈
  • 非常感谢。两种解决方案都能正常工作。那么如果我们要返回一个数组,而不是一个对象,我们应该怎么做呢?例如: [{ "name": "Jack", "workspaces": [ { "_id": "61216512315615645jbk", "permissions": [ "CAN_DELETE_WORKSPACE", "CAN_EDIT_PROJECT" ] }, { "_id": "41ss16512315615645bk" , "权限": [ "CAN_DELETE_WORKSPACE", "CAN_EDIT_PROJECT" ] } ] }]
  • 过滤器方法将返回一个数组。这不是最好的解决方案,因为它会在找到匹配项后查看所有内容。对于查找,您可以将其包装在一个数组中 const active = [users.find()];
【解决方案2】:

我调整了 Joe 提供的数据,因此他没有权限

const users = [{
    name: "Jack",
    workspaces: [{
        _id: "61216512315615645jbk",
        permissions: ["CAN_DELETE_WORKSPACE", "CAN_EDIT_PROJECT"],
      },
      {
        _id: "41ss16512315615645bk",
        permissions: ["CAN_DELETE_WORKSPACE", "CAN_EDIT_PROJECT"],
      },
    ],
  },
  {
    name: "Joe",
    workspaces: [{
      _id: "61216512315615645bk",
      permissions: ["CAN_DELETE_WORKSPACE"],
    }, ],
  },
];

const activeWorkspace = {
  name: "W1",
  _id: "61216512315615645jbk",
};

function findPermittedUser() {
  return users.filter(user => {
    let hasPermission = false

    user.workspaces.forEach(workspace => {
      if (activeWorkspace._id == workspace._id) {
        hasPermission = true
      }
    })

    return hasPermission
  })
}


console.log(findPermittedUser())

【讨论】:

  • 您的方法的问题是您查看所有内容。您不必查看每个索引。你应该使用 some 而不是 forEach 所以你不要那样做。
【解决方案3】:

您可以使用mapfilterusers 对象中“过滤”掉不需要的ID。类似的东西:

const users = [
    {
        "name": "Jack",
        "workspaces": [
            {
                "_id": "61216512315615645jbk",
                "permissions": [
                    "CAN_DELETE_WORKSPACE",
                    "CAN_EDIT_PROJECT"
                ]
            },
            {
                "_id": "41ss16512315615645bk",
                "permissions": [
                    "CAN_DELETE_WORKSPACE",
                    "CAN_EDIT_PROJECT"
                ]
            }
        ]
    },
    {
        "name": "Joe",
        "workspaces": [
            {
                "_id": "61216512315615645jbk",
                "permissions": [
                    "CAN_DELETE_WORKSPACE"
                ]
            }
        ]
    }
]

const activeWorkspace = {
  name: "W1",
  _id: "61216512315615645jbk",
};


const filteredUsers = users.map(item => ({ 
  name : item.name, 
  workspaces: item.workspaces.filter(user => user._id === activeWorkspace._id)}
));

console.log(filteredUsers);

【讨论】:

    【解决方案4】:

    这应该可以工作(经过测试):

    const filteredUsers = users.filter(
     user => user.workspaces.reduce(
      (acc, workspace) => acc || workspace._id === activeWorkspace._id, false)
     )
    )
    

    说明: 从代码中可以看出,我们正在使用 filterreduce。代码所做的非常简单,首先,我们要在用户数组上应用filter。现在在过滤器中,我们需要定义逻辑,只要我们的条件为真,它就应该返回true。 由于我们有一个工作区数组,我们需要遍历所有这些以检查我们的 activeWorkspace._id 是否存在于其中任何一个中。为此,您可以使用 for 循环并在找到时返回 true,否则返回 false。但这样做的功能性方法是使用reduce 并使用false 初始化累加器。每次访问工作区时,都会返回 acc || <our condition>。请注意,即使我们的条件返回 true,累加器也会在 reduce 的其余执行过程中变为 true。这在性能上稍差,因为您没有在找到工作区后立即退出。_id 就像在 for 循环的情况下所做的那样。

    【讨论】:

    • 不需要使用reduce。你正在重新发明 some()
    • @epascarello 谢谢。直到关于some()。傻我。
    【解决方案5】:

    users.map(u => u.workspaces).flat().filter(w => w._id === activeWorkspaceId);

    https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/flat

    【讨论】:

    • 这很容易放入堆栈 sn-ps 并显示结果。另外,请解释如何,为什么这样做,以便其他人可以从您的智慧中受益。如果您提高答案的质量,我将删除我的反对票。
    • .map(...).flat() 可以替换为.flatMap(...)
    • 我不记得这是添加的。如果仍然开放,我将在稍后有时间时更新。有趣的是,寻找“flatten javascript”并没有在谷歌上返回很好的答案,而是展示了语言的演变stackoverflow.com/questions/10865025/…
    猜你喜欢
    • 2021-08-26
    • 2021-03-15
    • 2020-11-23
    • 1970-01-01
    • 2019-06-20
    • 1970-01-01
    • 2020-08-25
    • 1970-01-01
    • 2022-01-02
    相关资源
    最近更新 更多