Arrays Ruby: select (), collect () e map ()

106

A sintaxe para mapeamento:

a = ["a", "b", "c", "d"]      #=> ["a", "b", "c", "d"] 
a.map {|item|"a" == item}     #=> [true, false, false, false] 
a.select {|item|"a" == item}  #=> ["a"]

Pergunta, se eu tenho:

 irb(main):105:0> details[1]
 => {:sku=>"507772-B21", :desc=>"HP 1TB 3G SATA 7.2K RPM LFF (3 .", :qty=>"", 
 :qty2=>"1", :price=>"5,204.34 P"}

Quero excluir todas as entradas que têm um valor de qty vazio nesta matriz ou selecionar apenas aquelas com algum valor.

Eu tentei:

details.map {|item|"" == item}

Apenas retorna muito falso e então quando eu uso o mesmo, apenas altero o mapa para selecionar Eu obtenho:

[]
ingalcala
fonte
Se você olhar de perto, parece que é uma variedade de hashes
Emily,
@Emily: É verdade, acabei de perceber isso. A última amostra de código me fez pensar o contrário, porque :qtynem aparece lá.
Niklas B.

Respostas:

131

Parece detailsuma matriz de hashes. Portanto, itemdentro do seu bloco estará todo o hash. Portanto, para verificar a :qtychave, você faria algo como o seguinte:

details.select{ |item| item[:qty] != "" }

Isso lhe dará todos os itens em que a :qtychave não é uma string vazia.

documentação oficial selecionada

Emily
fonte
26

EDIT: Acabei de perceber que você deseja filtrar details, que é uma matriz de hashes. Nesse caso, você poderia fazer

details.reject { |item| item[:qty].empty? }

A própria estrutura de dados interna não é um Array, mas um Hash. Você também pode usar selectaqui, mas o bloco recebe a chave e o valor neste caso:

irb(main):001:0> h = {:sku=>"507772-B21", :desc=>"HP 1TB 3G SATA 7.2K RPM LFF (3 .", :qty=>"", :qty2=>"1", :price=>"5,204.34 P"}
irb(main):002:0> h.select { |key, value| !value.empty? }
=> {:sku=>"507772-B21", :desc=>"HP 1TB 3G SATA 7.2K RPM LFF (3 .", 
    :qty2=>"1", :price=>"5,204.34 P"}

Ou usando reject, que é o inverso de select(exclui todos os itens para os quais a condição dada é válida):

h.reject { |key, value| value.empty? }

Observe que este é Ruby 1.9. Se você precisa manter a compatibilidade com 1.8, você pode fazer:

Hash[h.reject { |key, value| value.empty? }]
Niklas B.
fonte
@ingalcala: Acabei de perceber que minha resposta não é exatamente o que você precisa. Por favor, verifique minha edição para saber como filtrar o detailspróprio array.
Niklas B.
9

Ao lidar com um hash {}, use a chave e o valor para o bloco dentro do ||.

details.map {|key,item|"" == item}

=>[false, false, true, false, false]
Michael Berkowski
fonte