代码之家  ›  专栏  ›  技术社区  ›  Steve

如何提高?

  •  1
  • Steve  · 技术社区  · 16 年前

    我想知道是否有人能指出一个更干净更好的方法来写我的代码,这是粘贴在这里。代码从yelp中提取一些数据并将其处理为json格式。我不使用的原因 hash.to_json

    • text=保存到文件的输出

    def mineLocation
    
      client = Yelp::Client.new
      request = Yelp::Review::Request::GeoPoint.new(:latitude=>13.3125,:longitude => -6.2468,:yws_id => 'nicetry')
      response = client.search(request) 
      response['businesses'].length.times do |businessEntry|
        text =""
         response['businesses'][businessEntry].each { |key, value|
            if value.class == Array 
              value.length.times { |arrayEntry|
                text+= "\"#{key}\":["
                 value[arrayEntry].each { |arrayKey,arrayValue|
                  text+= "{\"#{arrayKey}\":\"#{arrayValue}\"},"
                 }
                 text+="]"   
              }
            else 
                  text+="\"#{arrayKey}\":\"#{arrayValue}\"," 
            end
           }
      end
     end
    
    4 回复  |  直到 14 年前
        1
  •  8
  •   Jörg W Mittag    13 年前

    require 'json'
    
    def mine_location
      client = Yelp::Client.new
      request = Yelp::Review::Request::GeoPoint.new(latitude: 13.3125,
        longitude: -6.2468, yws_id: 'nicetry')
      response = client.search(request)
    
      return response['businesses'].to_json
    end
    

    这对我来说很好。

    如果,不管出于什么原因 必须 编写自己的JSON发射器实现,这里有几个提示。

    在代码中您完全忽略的第一件事是Ruby是一种面向对象的语言,更确切地说是一种基于类的面向对象语言。这意味着通过构建一个对象网络来解决问题,这些对象通过消息传递相互通信,并通过执行在这些对象所属的类中定义的方法来响应这些消息。

    这给了我们很多功能:动态调度、多态性、封装和其他许多功能。利用这些,您的JSON发射器将如下所示:

    class Object
      def to_json; to_s                                                         end
    end
    
    class NilClass
      def to_json; 'null'                                                       end
    end
    
    class String
      def to_json; %Q'"#{to_s}"'                                                end
    end
    
    class Array
      def to_json; "[#{map(&:to_json).join(', ')}]"                             end
    end
    
    class Hash
      def to_json; "{#{map {|k, v| "#{k.to_json}: #{v.to_json}" }.join(', ')}}" end
    end
    

    mine_location 看起来和上面一样,除了明显没有 require 'json' 部分。

    class Object
      def to_json(*) to_s    end
    end
    
    class String
      def to_json(*) inspect end
    end
    
    class Array
      def to_json(indent=0)
        "[\n#{'  ' * indent+=1}#{
          map {|el| el.to_json(indent) }.join(", \n#{'  ' * indent}")
        }\n#{'  ' * indent-=1}]"
      end
    end
    
    class Hash
      def to_json(indent=0)
        "{\n#{'  ' * indent+=1}#{
          map {|k, v|
            "#{k.to_json(indent)}: #{v.to_json(indent)}"
          }.join(", \n#{'  ' * indent}")
        }\n#{'  ' * indent-=1}}"
      end
    end
    

    实际上,这段代码中没有Ruby特有的东西。这差不多 确切地

    唯一特定于语言的是如何“修改”类并向它们添加方法。在Ruby或Python中,只需修改类。在C和visualbasic.NET中,可能会使用扩展方法,在Scala中可能会使用隐式转换,在Java中可能会使用Decorator设计模式。

    你的代码的问题是你试图解决一个 递归而不是真正的递归。这只是 不能 工作。您编写的代码基本上是Fortran-57代码:没有对象和递归的过程性代码。即使只是搬家

    def jsonify(o)
      case o
      when Hash
        "{#{o.map {|k, v| "#{jsonify(k)}: #{jsonify(v)}" }.join(', ')}}"
      when Array
        "[#{o.map(&method(:jsonify)).join(', ')}]"
      when String
        o.inspect
      when nil
        'null'
      else
        o.to_s
      end
    end
    

    当然,你可以在这里玩同样的游戏:

    def jsonify(o, indent=0)
      case o
      when Hash
        "{\n#{'  ' * indent+=1}#{
          o.map {|k, v|
            "#{jsonify(k, indent)}: #{jsonify(v, indent)}"
          }.join(", \n#{'  ' * indent}") }\n#{'  ' * indent-=1}}"
      when Array
        "[\n#{'  ' * indent+=1}#{
          o.map {|el| jsonify(el, indent) }.join(", \n#{'  ' * indent}") }\n#{'  ' * indent-=1}]"
      when String
        o.inspect
      when nil
        'null'
      else
        o.to_s
      end
    end
    

    下面是 puts mine_location to_json 或者第二个版本的 jsonify ,其实并不重要,它们都有相同的输出:

    [
      {
        "name": "Nickies",
        "mobile_url": "http://mobile.yelp.com/biz/yyqwqfgn1ZmbQYNbl7s5sQ",
        "city": "San Francisco",
        "address1": "466 Haight St",
        "zip": "94117",
        "latitude": 37.772201,
        "avg_rating": 4.0,
        "address2": "",
        "country_code": "US",
        "country": "USA",
        "address3": "",
        "photo_url_small": "http://static.px.yelp.com/bpthumb/mPNTiQm5HVqLLcUi8XrDiA/ss",
        "url": "http://yelp.com/biz/nickies-san-francisco",
        "photo_url": "http://static.px.yelp.com/bpthumb/mPNTiQm5HVqLLcUi8XrDiA/ms",
        "rating_img_url_small": "http://static.px.yelp.com/static/20070816/i/ico/stars/stars_small_4.png",
        "is_closed": false,
        "id": "yyqwqfgn1ZmbQYNbl7s5sQ",
        "nearby_url": "http://yelp.com/search?find_loc=466+Haight+St%2C+San+Francisco%2C+CA",
        "state_code": "CA",
        "reviews": [
          {
            "rating": 3,
            "user_photo_url_small": "http://static.px.yelp.com/upthumb/ZQDXkIwQmgfAcazw8OgK2g/ss",
            "url": "http://yelp.com/biz/yyqwqfgn1ZmbQYNbl7s5sQ#hrid:t-sisM24K9GvvYhr-9w1EQ",
            "user_url": "http://yelp.com/user_details?userid=XMeRHjiLhA9cv3BsSOazCA",
            "user_photo_url": "http://static.px.yelp.com/upthumb/ZQDXkIwQmgfAcazw8OgK2g/ms",
            "rating_img_url_small": "http://static.px.yelp.com/static/20070816/i/ico/stars/stars_small_3.png",
            "id": "t-sisM24K9GvvYhr-9w1EQ",
            "text_excerpt": "So I know gentrification is supposed to be a bad word and all (especially here in SF), but the Lower Haight might benefit a bit from it. At least, I like...",
            "user_name": "Trey F.",
            "mobile_uri": "http://mobile.yelp.com/biz/yyqwqfgn1ZmbQYNbl7s5sQ?srid=t-sisM24K9GvvYhr-9w1EQ",
            "rating_img_url": "http://static.px.yelp.com/static/20070816/i/ico/stars/stars_3.png"
          },
          {
            "rating": 4,
            "user_photo_url_small": "http://static.px.yelp.com/upthumb/Ghwoq23_alkaXawgqj7dBA/ss",
            "url": "http://yelp.com/biz/yyqwqfgn1ZmbQYNbl7s5sQ#hrid:8xTNOC9L5ZXwGCMNYY-pdQ",
            "user_url": "http://yelp.com/user_details?userid=4F2QG3adYIUNXplqqp9ylA",
            "user_photo_url": "http://static.px.yelp.com/upthumb/Ghwoq23_alkaXawgqj7dBA/ms",
            "rating_img_url_small": "http://static.px.yelp.com/static/20070816/i/ico/stars/stars_small_4.png",
            "id": "8xTNOC9L5ZXwGCMNYY-pdQ",
            "text_excerpt": "This place was definitely a great place to chill. The atmosphere is very non-threatening and very neighborly. I thought it was cool that they had a girl dj...",
            "user_name": "Jessy M.",
            "mobile_uri": "http://mobile.yelp.com/biz/yyqwqfgn1ZmbQYNbl7s5sQ?srid=8xTNOC9L5ZXwGCMNYY-pdQ",
            "rating_img_url": "http://static.px.yelp.com/static/20070816/i/ico/stars/stars_4.png"
          },
          {
            "rating": 5,
            "user_photo_url_small": "http://static.px.yelp.com/upthumb/q0POOE3vv2LzNg1qN8MMyw/ss",
            "url": "http://yelp.com/biz/yyqwqfgn1ZmbQYNbl7s5sQ#hrid:pp33WfN_FoKlQKJ-38j_Ag",
            "user_url": "http://yelp.com/user_details?userid=FmcKafW272uSWXbUF2rslA",
            "user_photo_url": "http://static.px.yelp.com/upthumb/q0POOE3vv2LzNg1qN8MMyw/ms",
            "rating_img_url_small": "http://static.px.yelp.com/static/20070816/i/ico/stars/stars_small_5.png",
            "id": "pp33WfN_FoKlQKJ-38j_Ag",
            "text_excerpt": "Love this place!  I've been here twice now and each time has been a great experience.  The bartender is so nice.  When we had questions about the drinks he...",
            "user_name": "Scott M.",
            "mobile_uri": "http://mobile.yelp.com/biz/yyqwqfgn1ZmbQYNbl7s5sQ?srid=pp33WfN_FoKlQKJ-38j_Ag",
            "rating_img_url": "http://static.px.yelp.com/static/20070816/i/ico/stars/stars_5.png"
          }
        ],
        "phone": "4152550300",
        "neighborhoods": [
          {
            "name": "Hayes Valley",
            "url": "http://yelp.com/search?find_loc=Hayes+Valley%2C+San+Francisco%2C+CA"
          }
        ],
        "rating_img_url": "http://static.px.yelp.com/static/20070816/i/ico/stars/stars_4.png",
        "longitude": -122.429926,
        "categories": [
          {
            "name": "Dance Clubs",
            "category_filter": "danceclubs",
            "search_url": "http://yelp.com/search?find_loc=466+Haight+St%2C+San+Francisco%2C+CA&cflt=danceclubs"
          },
          {
            "name": "Lounges",
            "category_filter": "lounges",
            "search_url": "http://yelp.com/search?find_loc=466+Haight+St%2C+San+Francisco%2C+CA&cflt=lounges"
          },
          {
            "name": "American (Traditional)",
            "category_filter": "tradamerican",
            "search_url": "http://yelp.com/search?find_loc=466+Haight+St%2C+San+Francisco%2C+CA&cflt=tradamerican"
          }
        ],
        "state": "CA",
        "review_count": 32,
        "distance": 1.87804019451141
      }
    ]
    
        2
  •  8
  •   brad    16 年前

    我注意到的第一件事就是你对

    response['businesses'].length.times do |i|
      # the business you want is response['businesses'][i]
    end
    

    用于迭代。使用Array.each可以大大简化这一过程,它为您提供:

    response['businesses'].each do |businessEntry|
      # here, businessEntry is the actual object, so forego something like
      # response['business'][businessEntry], just use businessEntry directly
    end
    

    你实际上在用你的手机做同样的事情:

    注意样式,如果您的块在多行上,{}如果块是一行,则通常(尽管没有强制)使用do/end。

    另外,不确定为什么要在字符串中构建这些键/值对,只需做一个哈希。然后您可以很容易地转换为json,或者正如Jorg所指出的,只需将整个响应转换为json,而json正是您手动执行的操作。。。除非您需要首先处理数据(看起来您不需要这样做)

        3
  •  2
  •   mikej heading_to_tahiti    16 年前

    我很想看看你所犯的错误 hash.to_json

    就您的Ruby代码而言,有几个观察结果:

    • .length.times 做。。是一个 有点奇怪当你可以用 each 例如 response['businesses'].each do

    • 在你的 else text+="\"#{arrayKey}\":\"#{arrayValue}\"," 看起来像 arrayKey arrayValue 它们仅用作块 中的变量 每个 上面。

    • text ="" 将文本设置回空 每次迭代外部 看代码的样子 就像由 丢弃的。

        4
  •  2
  •   grg-n-sox    16 年前

    我不是Ruby方面的专家,但我知道如果它们出现在我的代码中,我的教授会对我大喊大叫。Mikej已经知道了一些重要的事情,尤其是使用 #each 而不是 #length #times .

    如果我在某种集合中进行迭代,那么我唯一一次使用 当我需要使用自定义迭代器时,即使这样,您仍然可以使用 for i in Range.new( begin, end, optional_exclusion ) 声明。这仍然可以在一个块中变成一个条件 #每个

    Mikej已经指出了在if语句的else部分调用arrayKey和arrayValue时作用域的错误,所以我不必担心。他也已经指出,你可能应该移动你的 text =""

    在那之后,我唯一关心的不是代码本身的问题,而是更多的编码风格和Ruby社区普遍实践的事情。所以这些建议,绝不是你必须接受的。它只是让阅读Ruby代码变得更容易。

    结束

    end 关键字并输入它刚刚关闭的作用域的名称。它将我从许多范围错误中解救出来,但我从未听说过有人这样做,而且它可能会用这些随机的结束行注释来混乱代码,但它是一种很好地为我服务的方法。

    我的第三个建议是改进你对弦和符号的使用。我几乎不敢这么说,因为我仍然需要提高对Ruby中符号的理解,而且我不记得在最近的任何脚本中使用过Yelp类,所以我对这一点一无所知。但是,看起来您使用了字符串 'businesses' '业务' 在内部的每个块和每个块中,您可能会将该字符串分配O(n)次(尽管内部块的分配在下一次迭代中会被垃圾收集)。然而,如果使用“:businesses”这样的符号,它只初始化一次。你也是这样 行,您应该将其修改为单个引号字符串文本。Ruby解释器可以比双引号更快地解析单引号字符串文本,所以一般来说,如果可以使用单引号字符串文本,就这样做。

    我所得到的只是一些建议。你需要或想要什么就拿什么。这里也会是你的代码看起来像假设你接受了我的建议,我没有打破任何过程。

    def mineLocation
    
      client = Yelp::Client.new
      request = Yelp::Review::Request::GeoPoint.new(:latitude=>13.3125,
                                                    :longitude => -6.2468,
                                                    :yws_id => 'nicetry')
      response = client.search(request)
      text = ''
      response[:businesses].each do |businessEntry|
        response[:businesses][businessEntry].each do |key, value|
          if value.kindOf( Array )
            value.each do |arrayEntry|
              text += "\"#{key}\":["
              value[arrayEntry].each do |arrayKey, arrayValue|
                text += "{\"#{arrayKey}\":\"#{arrayValue}\"},"
              end #each
              text += ']'   
            end #each
          else
            # Didn't fix because I didn't know you intentions here.
            text += "\"#{arrayKey}\":\"#{arrayValue}\"," 
          end #if
        end #each
      end #each
    
    end #def
    

    'nicetry' 因为我不知道Yelp类是如何工作的,可能需要一个字符串而不是一个符号。我也不知道预期的代码效果是什么,因为这段代码执行的唯一时间是变量超出范围时,所以我无法知道您在那一行中试图引用什么。特别是因为在这一点上,你的值也不是数组。

    我知道这是一个很长的答案,但我希望这有一些帮助!

    推荐文章