How can I display a Regexp output in an Alphabetical list?

后端 未结 2 1901
不知归路
不知归路 2021-01-21 13:54

I\'m new to coding and new to learning the language Ruby. I\'ve made progress on my code of a letter histogram. I\'m now at a point where I\'m struggling.

class          


        
相关标签:
2条回答
  • 2021-01-21 14:19

    Good start :)

    In order to make a method private, place it after a call to private in the class:

    class foo
      # all methods are public by default
      def something_public
        # …
      end
    
      private
      # makes all methods after this call private
      def something_internal
        # …
      end
    end
    

    Alternatively, you can call private with the symbol name of the method you want to make private (after it has been defined): private :something_internal. In newer versions of ruby defining a method returns the method name (as a symbol), so you can also do this:

    private def something_internal
      # …
    end
    

    to make just the one method private.

    In ruby, "private" means that you can't call the method with a dot, e.g. foo.something_internal will raise a NoMethodError if something_internal is a private method on foo. That means that to call a private method, you need to be in a method in the same class:

    class foo
      # …
    
      def something_public
        if something_internal # method called without a dot
          'the internal check was truth'
        else
          'the internal check was falsey'
        end
      end
    
      # …
    end
    

    Private methods are usually used to create helpers for the class that don't make sense to be called from outside the class, or that can cause bugs if they are called at the wrong time. In ruby, you can call a private method anyway if you really want by using send: foo.send(:something_internal, 'some', 'arguments'). But generally, you shouldn't need to, and you should rethink your code and see if you can refactor it to not need to call send.

    Also, by convention in ruby, method names are snake_cased and usually don't start with a capital (although the language allows this).

    0 讨论(0)
  • 2021-01-21 14:33

    I suggest you construct your class as follows.

    class Letter
      def initialize(text)                                  # 1
        @text = text
      end
    
      def display
        h = calculate_frequencies                           # 2
        ('a'..'z').each { |ltr|
          puts "%s%s" % [ltr, '*' * h.fetch(ltr, 0)] }      # 3
      end
    
      private                                               # 4
    
      def calculate_frequencies                             # 5
        @text.downcase.
              each_char.                                    # 6
              with_object(Hash.new(0)) { |c, letters|       # 7
                letters[c] += 1 if c.match?(/\p{Lower}/) }  # 8
      end
    end
    

    str = "Now is the time for all Rubyists to come to the aid of their bowling team."
    
    ltr = Letter.new(str)
    ltr.display
    a***
    b**
    c*
    d*
    e******
    f**
    g*
    h***
    i******
    j
    k
    l***
    m***
    n**
    o*******
    p
    q
    r***
    s***
    t********
    u*
    v
    w**
    x
    y*
    z
    

    Notes

    1

    text should be an argument of initialize so the methods can be used for any string, rather than for just one hard-wired string. @letters should not be initialized here as it needs to be initialized in calculate_frequencies each time that method is called (and there it need not be an instance variable).

    2

    For str, calculate_frequencies returns

    ltr.send(:calculate_frequencies) 
      #=> {"n"=>2, "o"=>7, "w"=>2, "i"=>6, "s"=>3, "t"=>8, "h"=>3, "e"=>6,
      #    "m"=>3, "f"=>2, "r"=>3, "a"=>3, "l"=>3, "u"=>1, "b"=>2, "y"=>1,
      #    "c"=>1, "d"=>1, "g"=>1}
    

    Object#send invokes private methods, as well as ones that are public or protected.

    3

    See Hash#fetch and String#*.

    4

    All methods defined after the invocation of the keyword private are private, until and if the keyword public or protected is encountered. Alternatively, one can define a single private method as private def calculate_frequencies; ... ; end. Also a public (or protected) method m may be made private by executing private m.

    5

    One of Ruby's conventions is to use snake-case for names of variables and methods. You don't have to follow that convention but 99%+ of Rubyists do.

    6

    String#each_char returns an enumerator, whereas String#chars returns an array. The latter should only be used when an array is needed or it is chained to an Array method; otherwise, each_char is preferable because it does not create an unneeded temporary array.

    7

    See Enumerator#with_object.

    8

    Rather than matching everything other than spaces, you probably want to only match letters. Note how I've used if here to avoid the need for two statements. See String#match?. One could instead write c =~ /\p{Lower}/ or c[/\p{Lower}/]. \p{Lower} (or [[:lower:]]) matches any Unicode lower-case letter, which generally is preferable to /[a-z]/. Even for English text, one may encounter words having letters with diacritical marks, such as née, Señor, exposé and rosé. "é".match? /[a-z]/ #=> false but "é".match? /\p{Lower}/ #=> true. Search the doc Regexp for \p{Lower} and [[:lower:]].

    0 讨论(0)
提交回复
热议问题