【问题标题】:In a map operation, how do I filter out a specific record?在 map 操作中,如何过滤掉特定的记录?
【发布时间】:2014-12-24 03:00:50
【问题描述】:

我有一条记录,当我返回一个关联的关联时,它会向我发回一个集合,其中还包括初始关联的记录。如何过滤掉原始记录?我知道这听起来令人困惑,但下面的代码应该是不言自明的。

基本上我有一条记录d,当从这个查询返回最终结果时 - d.parents.flat_map(&:children).uniq 我不希望它包含d 引用的记录。我如何以 Ruby 风格的方式做到这一点?如果有一个 Rails 或 Ruby 内置方法可以做到这一点,那将是完美的,所以我可以将它优雅地链接到我现有的查询,但我怀疑可能是这种情况......不过我很有希望......所以额外如果你能提供的话就加分。

[91] pry(main)> d
=> #<User id: 2, email: "def@test.com", encrypted_password: "$2a$Bne..", reset_password_token: nil, reset_password_sent_at: nil, gender: 0>
[92] pry(main)> d.parents
=> [#<User id: 1, email: "abc@test.com", encrypted_password: "$2a$10$...", reset_password_token: nil, reset_password_sent_at: nil, gender: 0>,
 #<User id: 4, email: "jkl@test.com", encrypted_password: "$2a$...", reset_password_token: nil, reset_password_sent_at: nil, gender: 1>]
[94] pry(main)> d.parents.flat_map(&:children).uniq
=> [#<User id: 2, email: "def@test.com", encrypted_password: "$2a$10$...", reset_password_token: nil, reset_password_sent_at: nil, gender: 0>,
 #<User id: 3, email: "ghi@test.com", encrypted_password: "$2a$10$...", reset_password_token: nil, reset_password_sent_at: nil, gender: 1>,
 #<User id: 5, email: "mno@test.com", encrypted_password: "$2a$10$.mXgmN...", reset_password_token: nil, reset_password_sent_at: nil, gender: 1>]

编辑 1

这是我的关联结构:

class User < ActiveRecord::Base
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable and :omniauthable
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :trackable, :validatable

  attr_accessible :email, :password, :password_confirmation, :gender

  has_one :family_tree
  has_many :nodes
  has_many :relationships

  has_many :parent_child_relationships, class_name: "Relationship", foreign_key: :child_id
  has_many :parents, through: :parent_child_relationships, source: :parent

  has_many :child_parent_relationships, class_name: "Relationship", foreign_key: :parent_id      
  has_many :children, through: :child_parent_relationships, source: :child

  enum gender: [ :male, :female ]

  def has_children?
    !children.empty?
  end

  def has_parents?
    !parents.empty?
  end

end

这是我的Relationship.rb 模型:

class Relationship < ActiveRecord::Base
  belongs_to :parent, class_name: "User"
  belongs_to :child, class_name: "User"

  attr_accessible :parent_id, :child_id
end

【问题讨论】:

  • 我认为您想获取用户的兄弟姐妹。看看我的回答。它提供了一个更快的选择。
  • 谢谢,我会删除我的,因为它不需要恕我直言 - Humza 已经掌握了这一点。我建议更新您的标题以匹配问题,以便帮助人们在这里搜索;可能带有关键字 parent、child、siblings、activerecord 等的东西。

标签: ruby-on-rails ruby


【解决方案1】:
d.parents.flat_map(&:children).uniq.reject{ |c| c == d }

d.parents.flat_map(&:children).uniq - [d]

但我认为您正在尝试获取用户的兄弟姐妹。如果您有模型设置,那么您应该执行以下操作:

class User < ActiveRecord::Base
  has_many :parents # with keys and class_name pointing to the same class
  has_many :children # with keys and class_name pointing to the same class

  has_many :parents_children, through: :parents, source: :children

  def siblings
    self.parents_children.where("users.id != ?", self.id)
  end
end

d.siblings # what you want

我想不出将users.id != self.id 条件传递给has_many 关系的方法,否则has_many :siblings, options 将是理想的。

【讨论】:

  • 我真的很喜欢这种方法,而这正是我真正想要的。你认为这比我之前做的ruby 查询更好吗?即性能更高?
  • 是的。这样会更有效率。除了 Ruby 过滤之外,您之前为每个父级查询数据库一次。这样,您将只查询一次数据库。而且你不会得到重复的孩子。
  • 我刚刚用关于我的关联的详细信息更新了这个问题 - 特别是我正在通过另一个模型 - Relationships 处理我的 parentchild 关系。鉴于这种结构,我将如何应用您的答案?我怀疑你的has_many :parents_children... 会起作用......不是吗?
  • 它应该可以工作。您仍然有 has_many :parentshas_many :children 返回 users ,如我的示例所示。
  • 是的。非常感谢!
【解决方案2】:

您可以使用Array#select() 从 Ruby 中的数组中过滤元素。

例子:

> a = [1,2,3]
> a.select{|x| not x.even?}.map{|x| x**2}
=> [1, 9]

在您的情况下,select 子句将忽略任何等于 d 的记录

【讨论】:

  • 你能重写我原来的flat_map 以包含select 还是会像joel 建议的那样放在最后?
  • 自己适应应该没那么难。
猜你喜欢
  • 1970-01-01
  • 2019-11-27
  • 1970-01-01
  • 1970-01-01
  • 2020-10-12
  • 2015-05-21
  • 2013-08-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多