Running with Ruby

Tag: Array

Ruby hash initializing – why do you think you have a hash, but you have an array

We all use hashes and it seems, that there’s nothing special about them. They are as dictionaries in Python, or any other similar structures available for multiple different languages. And that’s more or less true. Although Ruby hashes are really special, because from time to time they really are… arrays.

You won’t see that clearly until you either look into Ruby source code, or you benchmark it. Here is code and and results of my benchmark:

Benchmark

require 'benchmark'

GC.disable

ar = nil

100.times do |steps|
  d = Benchmark.measure {
    100000.times { ar = { a: 1, b: 2, c: 3, d: 4, e: 5, f: 6, g: 7, h: 8, i: 9, j: 10 } }
  }

  system("echo '#{ar.count}, #{d.real}' >> #{ar.count}.csv")
end

Benchmark results

hasharray

There’s a huge disproportion between 6 and 7 elements. And that’s the point where a Ruby “hashy array” becomes a real hash. To explain this, I will quote funny-falcon:

Investigation shows, that typical rails application allocates tons of small hashes. Up to 40% of whole allocated hashes never grows bigger than 1 element size.

That’s the primary reason of this patch. Small arrays are faster and use less memory than hashes. If you want to see the code, here’s a pull request with code that optimize arrays up to 6 elements.

Paginacja (pagination) z pomocą Kaminari a paginacja tablic (Array)

Korzystając z 254 Railscasta dot. paginacji z pomocą Kaminari, natknąłem się na problem paginacji tablic. Dawniej korzystałem z WillPagination i tworzyłem sobie instancję tego obiektu, wrzucając co mi tam trzeba. Paginowało ładnie. Niestety czasy się zmieniają i przyszło mi korzystać z Kaminari (które nawiasem mówiąc jest dużo wygodniejsze). Kaminari dodaje tylko scope’y – tak więc z definicji nie obsługuje niczego innego niż ActiveRecord.

Aby obejść ten problem, przygotowałem małe rozszerzenie klasy Array. Z racji tego, że paranoją byłoby ładować do tablicy wszystko (załóżmy że danych jest duuuużo), rozszerzenie to, działa na już “skróconym” (czy też zpaginowanym) zbiorze. Przykład:

Mamy 100 linijek tekstu, chcemy wyświetlać po 10 i skorzystać z paginacji. Wybieramy więc interesującą nas stronę:

@pagin_lines = @lines[20, 10]
@total_lines = @lines.count
@total_lines.paginable(3, 10, @total_lines)

I tyle. Parametry są następujące:

  1. page – na której stronie jesteśmy (którą stronę wyświetlamy),
  2. per_page – ile elementów na stronie,
  3. total_elements_amount – ile jest łącznie elementów.

I to by było na tyle. Cały kod też nie jest skomplikowany:

# Rozszerzenie klasy Array umożliwiające korzystanie z paginacji za pomocą
# pluginu Kaminaro
class Array
  def paginable(page, per_page, total_elements_amount)
    @paginate_page = page
    @paginate_per_page = per_page
    @paginate_total_elements_amount = total_elements_amount
    self.instance_eval <<-EVAL
      def current_page
        @paginate_page.to_i
      end

      def num_pages
        (@paginate_total_elements_amount/@paginate_per_page).floor.to_i
      end

      def limit_value
        @paginate_per_page.to_i
      end

    EVAL
  end
end

Od teraz możemy normalnie wykorzystywać tablicę@total_lines do paginacji:

<%= paginate @total_lines %>

Copyright © 2018 Running with Ruby

Theme by Anders NorenUp ↑