Map method does not work as expected

Asked

Viewed 150 times

4

I’m studying Ruby (no Rails, for now).

And I’m on the following scenario:

agenda.Rb

require 'set'

class Agenda

    def initialize
        @contatos = Set.new
    end

    def contatos
        @contatos.to_a
    end

    def query_by_email(email)
        contatos.flatten.select { |e| e.email == email }
    end

    def add(*contato)
        @contatos << contato
    end

end

Rb contact.

class Contato

    attr_accessor :nome
    attr_accessor :numero
    attr_accessor :email

    def initialize(nome, numero, email)
        @nome = nome
        @numero = numero
        @email = email
    end

    def hash
        email.hash
    end

    def eql?(other)
        other.class == self.class && other.email == @email
    end

    def to_s
        "Nome: #{@nome}, Numero: #{@numero}, Email: #{@email}"
    end

end

and my main.Rb class (which I use for testing..)

main.Rb

require File.expand_path("contato")
require File.expand_path("agenda")

agenda = Agenda.new

a = Contato.new('Rafael', '98-88891948', '[email protected]')
b = Contato.new('Rafael', '98-88891948', '[email protected]')
c = Contato.new('Renan', '98-88891948', '[email protected]')
d = Contato.new('Renan', '98-88891948', '[email protected]')
e = Contato.new('Renan', '98-88891948', '[email protected]')

agenda.add a,b,c,d,e

puts agenda.contatos.map(&:email)

the last line is returning me the following error:

main.Rb:14:in map': undefined methodemail' for # >> (Nameserver) from main.Rb:14:in `'

And I realized that if I add the method flatten, works as expected.

puts agenda.contatos.flatten.map(&:email)

I just don’t understand why, since the flatten does nothing special, just returns an array that already existed without making any kind of modification or if you want to change the type. Could someone explain to me why it worked?

(I am coming from java, the only 'functional' language I already work with is javascript)

  • Rafael by the reply of @Rohbarboza I thought of something else instead of using @contatos = Set.new you tried to use @contatos = []?

2 answers

3

As mentioned by @Roh Barboza, your #contatos is not returning a simple contact list. The real problem that needs to be fixed is not how you run the #map. The error is here:

def add(*contato)
    @contatos << contato
end

Within that function, contato is a contact list and not a single one. It is the list of arguments passed to the function. It should actually be implemented like this:

def add(*contatos)
    contatos.each do |contato|
        @contatos << contato
    end
end

That’s it. Everything else is correct and will work properly.

0

Currently its contact book. is returning this:

[
 [
  Nome: Rafael, Numero: 98-88891948, Email: [email protected],
  Nome: Rafael, Numero: 98-88891948, Email: [email protected],
  Nome: Renan,  Numero: 98-88891948, Email: [email protected],
  Nome: Renan,  Numero: 98-88891948, Email: [email protected], 
  Nome: Renan,  Numero: 98-88891948, Email: [email protected]
 ]
]

Your Array is inside another Array, use this:

agenda.contatos.flatten.map(&:email)

or

agenda.contatos.first.map(&:email) 
  • I did not understand why I voted against, the answer explains why the code only works with the flatten, seems to me the correct answer. + 1 to the @Rohbarboza reply

  • 1

    The need to use flatten in this case is a design error.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.