Post

Size, Length e Count: Qual a diferença?

Size, Length e Count: Qual a diferença?

Ruby é uma linguagem muito expressiva e que nos dá a liberdade de escrever código de várias formas. Por exemplo, se eu quiser contar quantos elementos tem numa lista, eu posso usar pelo menos 3 métodos diferentes para isso.

No Ruby

O length, que é um método usado em arrays, strings e hashes, retorna o número de elementos que o objeto tem.

1
2
3
4
5
  array = [1, 2, 3, 4, 5]
  puts array.length # => 5

  string = "Hello, World!"
  puts string.length # => 13

O método size é basicamente a mesma coisa que o length. Ele é um alias do método length.

1
2
3
4
5
  array = [1, 2, 3, 4, 5]
  puts array.size # => 5

  string = "Hello, World!"
  puts string.size # => 13

O count já é um pouco diferente. Além de contar o total, você pode passar um argumento ou um bloco para filtrar o que quer contar.

1
2
3
4
5
6
7
  numeros = [1, 2, 3, 4, 5, 6]
  
  # Quantos são pares?
  numeros.count(&:even?) # => 3
  
  # Quantas vezes aparece o número 2?
  numeros.count(2) # => 1

No Rails

E como funciona no ActiveRecord? Quando estamos trabalhando com ActiveRecord, a escolha entre esses métodos impacta diretamente a performance, já que cada um fala com o banco de dados de um jeito diferente.

O count quando você quer garantir que a contagem será feita diretamente no banco de dados. Sempre que ele for chamado ele vai executar uma consulta SQL para contar os registros.

1
2
3
4
5
ActiveRecord::Base.logger = Logger.new(STDOUT)
users = User.all
users.count # SELECT COUNT(*) FROM users => 1000
users.count # SELECT COUNT(*) FROM users => 1000

O length quando é chamado pela primeira vez vai executar uma query no banco de dados para contar os registros, e nas chamadas seguintes ele vai usar o valor que foi armazenado na memória.

1
2
3
4
5
6
7
ActiveRecord::Base.logger = Logger.new(STDOUT)
users = User.all
# O length carrega todos os registros para a memória
users.length # SELECT "users".* FROM "users" => 1000 registros transformados em objetos
users.length # 1000 (agora usa o que já está na memória)


Quando usamos o size ele consegue saber alternar entre o count e o length. Ele verifica se os registros foram carregados previamente, se sim ele usa o length, se não ele usa o count.

1
2
3
4
5
6
users = User.all
users.size # SELECT COUNT(*) FROM "users" (Ele viu que não estava carregado e foi direto pro banco)

users.load # Forçamos o carregamento dos registros
users.size # 1000 (Ele percebeu que já carregou e contou direto da memória)

Entender o comportamento real desses métodos é fundamental para evitar desperdício de recursos. Escolher o método certo para cada cenário é o que garante uma aplicação funcione de forma correta. Nos próximos posts pretendo mostrar outros métodos do Rails que causam confusão mas que são muito importantes para o dia a dia do desenvolvedor Rails.

Referências

count: https://apidock.com/rails/ActiveRecord/Calculations/count

length: https://docs.ruby-lang.org/en/master/Array.html#method-i-length

size: https://apidock.com/rails/ActiveRecord/Associations/CollectionProxy/size

Esta postagem está licenciada sob CC BY 4.0 pelo autor.