是否有更高效的方法来创建这个数组?

时间:2013-04-30 10:35:47

标签: ruby-on-rails ruby

对于我的一个视图我想要包含一个带有jqueries typeahead函数的搜索字段。

数组应包含客户端的所有属性值。

查询数组按以下方式生成:

@clients = []
Client.each do |client|
  @clients << client.attributes.values.join(' ')
end

这种方法对于大约3000个条目的数据集是否足够高效? 还是有更好更快的解决方案?

提前致谢。 干杯, 帕特里克

更新

一位用户提到要实现它:

@clients = Client.map do |client|
  client.attributes.values.join(' ')
end

这是另一种方法。但基准测试显示,这并没有改善业绩。

这给我留下了一个问题:也许有更高效的方式,但谈到最多3000条记录 - 这真的很重要吗?

3 个答案:

答案 0 :(得分:5)

您可以使用.map

@clients = Client.map do |client|
  client.attributes.values.join(' ')
end

答案 1 :(得分:4)

即使ActiveRecord模型实现了map方法(他们认为我们不相信),OP和@xdazz建议的两个解决方案在时间和内存复杂性方面是等价的。这可以通过这个简单的基准来观察:

require 'fruity'

# Dummy client class
class Client < Struct.new(:first_name, :last_name, :position, :company)
  class << self
    include Enumerable

    def each(&block)
      5000.times do
        yield Client.new('Firstname', 'Lastname', 'CEO', 'Company Inc.')
      end
    end
  end

  alias_method :attributes, :to_h
end


compare do
  schnika do
    clients = []
    Client.each do |client|
      clients << client.attributes.values.join(' ')
    end
    nil
  end

  xdazz do
    clients = Client.map do |client|
      client.attributes.values.join(' ')
    end
    nil
  end
end

将输出

schnika is similar to xdazz

此外,当您查看map(与collect同义)的实现时,很明显除了OP的方法之外没有其他任何事情发生:

static VALUE
rb_ary_collect(VALUE ary)
{
    long i;
    VALUE collect;

    RETURN_ENUMERATOR(ary, 0, 0);
    collect = rb_ary_new2(RARRAY_LEN(ary));
    for (i = 0; i < RARRAY_LEN(ary); i++) {
    rb_ary_push(collect, rb_yield(RARRAY_PTR(ary)[i]));
    }
    return collect;
}

这转换为:

class Array
  def collect
    collect = []
    self.each do |el|
      collect << yield(el)
    end
    collect
  end
end

答案 2 :(得分:1)

您可能不需要检索所有属性(例如'updated_at'),因此以下内容可能会更快:

@clients = Client.select([:name, :email, :id]).map do |client|
  client.attributes.values.join(' ')
end

添加了id,以防您需要链接到客户端。