@JanDvorak Esta questão não é apenas sobre retornar o subhash, mas também sobre como modificar um existente. Coisas muito semelhantes, mas o ActiveSupport tem meios diferentes para lidar com elas.
skalee
Respostas:
58
Se você deseja especificamente que o método retorne os elementos extraídos, mas h1 permaneça o mesmo:
Este é O (n2) - você terá um loop no select, outro loop no include que será chamado h1.size times.
metakungfu
1
Embora esta resposta seja decente para rubi puro, se você estiver usando trilhos, a resposta abaixo (usando integrado sliceou except, dependendo de suas necessidades) é muito mais limpa
Krease
137
ActiveSupport, Pelo menos uma vez 2.3.8, fornece quatro métodos convenientes: #slice, #excepte os seus homólogos destrutivas: #slice!e #except!. Eles foram mencionados em outras respostas, mas para resumi-los em um só lugar:
Observe os valores de retorno dos métodos bang. Eles não apenas adaptarão o hash existente, mas também retornarão entradas removidas (não mantidas). O que Hash#except!melhor se adequa ao exemplo dado na pergunta:
x ={a:1, b:2, c:3, d:4}# => {:a=>1, :b=>2, :c=>3, :d=>4}
x.except!(:c,:d)# => {:a=>1, :b=>2}
x
# => {:a=>1, :b=>2}
ActiveSupportnão requer Rails inteiros, é bem leve. Na verdade, muitas joias não-rails dependem dele, então provavelmente você já o tem em Gemfile.lock. Não há necessidade de estender a aula de Hash por conta própria.
O patch Mokey é definitivamente o caminho a seguir na IMO. Muito mais limpo e torna a intenção mais clara.
Romário
1
Adicione para modificar o código para endereçar corretamente o módulo do núcleo, definir o módulo e importar estender o núcleo do Hash ... módulo Módulo CoreExtensions Hash def slice (* keys) :: Hash [[keys, self.values_at (* keys)]. Transpose] end end fim Hash.include CoreExtensions :: Hash
Acho que você está descrevendo extrato !. extrair! remove as chaves do hash inicial, retornando um novo hash contendo as chaves removidas. fatia! faz o oposto: remove todas as chaves, exceto as especificadas, do hash inicial (novamente, retornando um novo hash contendo as chaves removidas). Então, corte! é um pouco mais como uma operação de "retenção".
Bom trabalho. Não é bem o que ele está pedindo. Seu método retorna: {: d =>: D,: b =>: B,: e => nulo,: f => nulo} {: c =>: C,: a =>: A,: d => : D,: b =>: B}
Andy
Uma solução equivalente de uma linha (e talvez mais rápida): <pre> def subhash(*keys) select {|k,v| keys.include?(k)} end
Aqui está uma solução funcional que pode ser útil se você não estiver executando o Ruby 2.5 e no caso de não querer poluir sua classe Hash adicionando um novo método:
Respostas:
Se você deseja especificamente que o método retorne os elementos extraídos, mas h1 permaneça o mesmo:
E se você quiser corrigir isso na classe Hash:
Se você deseja apenas remover os elementos especificados do hash, isso é muito mais fácil usando delete_if .
fonte
slice
ouexcept
, dependendo de suas necessidades) é muito mais limpaActiveSupport
, Pelo menos uma vez 2.3.8, fornece quatro métodos convenientes:#slice
,#except
e os seus homólogos destrutivas:#slice!
e#except!
. Eles foram mencionados em outras respostas, mas para resumi-los em um só lugar:Observe os valores de retorno dos métodos bang. Eles não apenas adaptarão o hash existente, mas também retornarão entradas removidas (não mantidas). O que
Hash#except!
melhor se adequa ao exemplo dado na pergunta:ActiveSupport
não requer Rails inteiros, é bem leve. Na verdade, muitas joias não-rails dependem dele, então provavelmente você já o tem em Gemfile.lock. Não há necessidade de estender a aula de Hash por conta própria.fonte
x.except!(:c, :d)
(com estrondo) deve ser# => {:a=>1, :b=>2}
. Bom se você puder editar sua resposta.Se você usa trilhos , o Hash # slice é o caminho a seguir.
Se você não usar rails , Hash # values_at retornará os valores na mesma ordem em que você os pediu, para que você possa fazer isso:
ex:
Explicação:
Fora de
{:a => 1, :b => 2, :c => 3}
nós queremos{:a => 1, :b => 2}
Se você acha que o patching do macaco é o caminho a percorrer, seguir o que você deseja:
fonte
Ruby 2.5 adicionado Hash # slice :
fonte
Você pode usar o slice! (* Keys) que está disponível nas extensões principais do ActiveSupport
initial_hash agora seria
extraído_slide seria agora
Você pode olhar para
slice.rb in ActiveSupport 3.1.3
fonte
fonte
def subhash(*keys) select {|k,v| keys.include?(k)} end
fonte
se você usa rails, pode ser conveniente usar Hash.except
fonte
fonte
Aqui está uma rápida comparação de desempenho dos métodos sugeridos,
#select
parece ser o mais rápidoO refinamento ficará assim:
E para usar:
fonte
Ambos
delete_if
ekeep_if
fazem parte do núcleo Ruby. Aqui você pode conseguir o que deseja sem corrigir oHash
tipo.Para obter mais informações, verifique os links abaixo da documentação:
fonte
Como outros mencionaram, Ruby 2.5 adicionou o método Hash # slice.
O Rails 5.2.0beta1 também adicionou sua própria versão do Hash # slice para reduzir a funcionalidade para usuários do framework que estão usando uma versão anterior do Ruby. https://github.com/rails/rails/commit/01ae39660243bc5f0a986e20f9c9bff312b1b5f8
Se estiver procurando implementar o seu próprio por qualquer motivo, é um bom forro também:
fonte
Este código injeta a funcionalidade que você está pedindo na classe Hash:
e produz os resultados que você forneceu:
Nota: este método realmente retorna as chaves / valores extraídos.
fonte
Aqui está uma solução funcional que pode ser útil se você não estiver executando o Ruby 2.5 e no caso de não querer poluir sua classe Hash adicionando um novo método:
Em seguida, você pode aplicá-lo até mesmo em hashes aninhados:
fonte
Apenas uma adição ao método de fatia, se as chaves de subhash que você deseja separar do hash original forem dinâmicas, você pode fazer como,
fonte
Podemos fazer isso fazendo um loop nas chaves que queremos extrair e verificando se a chave existe e depois extraí-la.
fonte