Ruby中作为散列键/集合条目的多部分值

oewdyzsn  于 2023-03-17  发布在  Ruby
关注(0)|答案(2)|浏览(106)

在Python中,我可以使用元组(或任何可散列对象)作为字典键或集合成员,这对于去重很有用:

cool_podcast_guests = set([
    ('Emma', 'Suter'),
    ('Dave', 'Warner'),
    ('Evie', 'Wilde'),
    ('Emma', 'Suter'),
]) 

for forename, surname in cool_podcast_guests:
    interview_these[(forename, surname)] = lookup_address(forename, surname)

这(简单地假设前名-姓氏对指的是唯一的人)消除了候选人列表中的重复项。
在Ruby中,您将如何做到这一点?

umuewwlo

umuewwlo1#

一些基本选项

如果您只想“自动”重复数据消除,您有几个基本选择:
1.使用Symbol而不是Array或String,因为根据定义,Symbol是唯一的。
1.使用String对象的Array作为键。
1.使用由部分名称组成的组合字符串来创建密钥。
1.使用Set而不是Hash,因为Set保证了对象的唯一性,而不是Hash键。
注意,当赋值给匹配的哈希键时,最后输入的值将覆盖已经存在的值。无论键的类型如何,都是如此;散列只能包含唯一键。
另外,注意Ruby实际上并没有元组,即使是“不可变”对象(除了Symbol)也很少是真正不可变的,即使是常量在Ruby中也可以被覆盖,尽管会有警告;这被语言维护者广泛认为是一个特性,而不是一个错误。

使用输入和省略代码的示例

假设你不担心两个拥有不同信息的人碰巧共享相同的名字和姓氏或一个共同的电子邮件地址,你可以简单地像这样分配你的值:

def scrape_address forename, surname
  # do whatever you want to do here
end

guests = [
    ['Emma', 'Suter'],
    ['Dave', 'Warner'],
    ['Evie', 'Wilde'],
    ['Emma', 'Suter'],
]

# Needs to be accessible outside the scope
# of the block below; there are other ways
# to do this, so consider this approach as
# only an illustration. Instance variables
# or closures would be good alternatives.
interview_contact_email = {}

# Use your existing lookup, relying on
# the uniqueness of `forename + surname`
# to actually be a unique key.
guests.map do |forename, surname|
  name  = [forename, surname].join " "
  email = scrape_address forename, surname
  interview_contact_email[name] = email
end

更好的选择

由于姓名、电子邮件和其他数据本身并不唯一,您可以考虑其他替代方案,例如为每个人分配一个UUIDv 4或唯一的数据库键作为ID,并将重复数据删除作为一个单独的练习。这是因为您无法保证数据集中不存在多个“Jane Doe”,或者“Jane Doe”和“John Doe”都使用jdoe@example.com作为共享电子邮件地址。
数据清理和验证的范围在很大程度上超出了您最初的问题的范围,但我在这里提到它是因为总会有人反对,认为假设名称形成唯一的键或多个键不能具有相同的值将把您引向黑暗面,在那里他们有美味的饼干。
有很多其他的方法可以做你想做的事情,但是只要你记住哈希键是唯一的,但是它们的值可以被覆盖,你就可以很容易地做你想做的事情。

参见

  • Hash,包括大量关于基本和自定义密钥对象语义的信息。
  • Symbol,当你想要Assertidentify而不是value时经常使用它,你最常看到的符号是哈希键或方法名,但它们是Ruby内部工作的基础。
  • String,这是当前包含在元组中的Ruby对象类型,它们有很多连接、连接、插值和各种转换的方法,允许您创建有意义的哈希键。
  • Random::Formatter#uuid可用于生成UUIDv 4标识符作为键,以防您 * 不 * 确定示例代码中名为Emma Suter的两个人实际上是同一个人。
f87krz0w

f87krz0w2#

这可以使用Ruby散列来完成,它可以将数组作为键:

n0 = [ :Dave, :Willis ]
n1 = [ :Sam, :Jones ]
guests = {n0 => 'addr1', n1 => 'addr2'}
guests.include?(n0) # => true
guests[n0] # => 'addr1'
n0.hash # => 110002110

注意Python和Ruby的语义是不同的,在Ruby中修改键的一个组成部分会破坏散列索引--所以不要在没有重新散列的情况下修改Ruby键:

n0[0] = :Emma
guests[n0] # => nil

但是:

guests.rehash # => {[:Emma, :Willis]=>'addr1', [:Sam, :Jones]=>'addr2'}
guests.include?(n0) # => true
guests[n0] # => 'addr1'

在Python中,元组可以是键(除非它们包含可变值),但列表不能:

>>> guests = {}
>>> tuple_dave = ('Dave', 'Warner')
>>> list_dave =   ['Dave', 'Warner']
>>> guests[tuple_dave] = "addr1"
>>> guests[list_dave] = "addr1"
TypeError: unhashable type: 'list'
>>> h = ('foo', ['bar', 'zot'])
>>> guests[h] = "addr3"
TypeError: unhashable type: 'list'
>>> guests
{('Dave', 'Warner'): 'addr1'}

在Python中,改变tuple_dave的值根本不会影响guests,重新赋值tuple_dave会创建一个与旧值无关的新元组。

>>> tuple_dave = ('Dave', 'Smith')
>>> guests
{('Dave', 'Warner'): 'addr1'}
>>> guests[tuple_dave] = "addr2"
>>> guests
{('Dave', 'Warner'): 'addr1', ('Dave', 'Smith'): 'addr2'}

在Python中,如果你想改变一个已经存在的字典条目的键,你不能这样做,你需要删除这个键,然后重新添加它。

相关问题