Upgrade to Pro — share decks privately, control downloads, hide ads and more …

The Audacious Array (RubyConf 2021)

The Audacious Array (RubyConf 2021)

What could be simpler than the array? It's just a list of indexed values, right?

Well, not so fast. Ruby reimagines what an array can be, turning it into a randomizer, a 2D map, a stack, a queue, and a mathematical set. It also provides built-in utilities for unparalleled analysis and search of its contents.

Understanding arrays deeply is a powerful step forward in writing concise, beautiful, semantic Ruby.

7b5a451ee25044b9c869e3e98b79425d?s=128

Ariel Caplan

November 10, 2021
Tweet

More Decks by Ariel Caplan

Other Decks in Technology

Transcript

  1. RUBYCONF 2021 Ariel Caplan • @amcaplan • amcaplan.ninja The Audacious

    Array
  2. None
  3. []

  4. CatWalk

  5. None
  6. https://github.com/amcaplan/catwalk

  7. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • • Ruby

    programmer since 2014 • Backend Developer at • Find me online: @amcaplan • https://amcaplan.ninja Hi! I’m Ariel Caplan.
  8. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • talk[0] #=>

    "basics"
  9. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • • Ordered

    collection of values • Values can be any Ruby object • Get/set by index (zero-based) • Literal syntax: • Explicit syntax: • Setting by index: • Strict fetching: • Standard retrieval: • Descriptive Information: What is an Array? [1, 2, 3] Array.new(3, :a) #=> [:a, :a, :a] array[2] #=> "val2" array[3] #=> nil array[1..2] #=> ["val1", "val2"] array[1..-1] #=> ["val1", “val2”] array.first #=> "val0" array.last #=> “val2" array.fetch(3) # IndexError (index 3 outside of array bounds: -3...3) array.size #=> 4 array.empty? #=> false array[2] = "val2"
  10. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • talk[1] #=>

    "adding and removing elements”
  11. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Front and

    Back array = [1, 2, 3, 4, 5] # adding items array.push(6) #=> [1, 2, 3, 4, 5, 6] array << 7 #=> [1, 2, 3, 4, 5, 6, 7] array.unshift(0) #=> [0, 1, 2, 3, 4, 5, 6, 7] # removing items array.pop #=> 7 array #=> [0, 1, 2, 3, 4, 5, 6] array.shift #=> 0 array #=> [1, 2, 3, 4, 5, 6]
  12. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Stack: #push

    and #pop class Stack def initialize @stack = [] end def push(item) @stack.push(item) end def pop @stack.pop end end
  13. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Stack: #push

    and #pop class Stack def initialize @stack = [] end def push(item) @stack.push(item) end def pop @stack.pop end end s = Stack.new
  14. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Stack: #push

    and #pop class Stack def initialize @stack = [] end def push(item) @stack.push(item) end def pop @stack.pop end end s = Stack.new s.push(:a) :a
  15. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Stack: #push

    and #pop class Stack def initialize @stack = [] end def push(item) @stack.push(item) end def pop @stack.pop end end s = Stack.new s.push(:a) s.push(:b) :a :b
  16. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Stack: #push

    and #pop class Stack def initialize @stack = [] end def push(item) @stack.push(item) end def pop @stack.pop end end s = Stack.new s.push(:a) s.push(:b) s.push(:c) :a :b :c
  17. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Stack: #push

    and #pop class Stack def initialize @stack = [] end def push(item) @stack.push(item) end def pop @stack.pop end end s = Stack.new s.push(:a) s.push(:b) s.push(:c) s.pop #=> :c :a :b
  18. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Stack: #push

    and #pop class Stack def initialize @stack = [] end def push(item) @stack.push(item) end def pop @stack.pop end end s = Stack.new s.push(:a) s.push(:b) s.push(:c) s.pop #=> :c s.pop #=> :b :a
  19. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Stack: #push

    and #pop class Stack def initialize @stack = [] end def push(item) @stack.push(item) end def pop @stack.pop end end s = Stack.new s.push(:a) s.push(:b) s.push(:c) s.pop #=> :c s.pop #=> :b s.pop #=> :a
  20. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Queue: #push

    and #shift class Queue def initialize @queue = [] end def push(item) @queue.push(item) end def pop @queue.shift end end
  21. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Queue: #push

    and #shift class Queue def initialize @queue = [] end def push(item) @queue.push(item) end def pop @queue.shift end end q = Queue.new
  22. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Queue: #push

    and #shift class Queue def initialize @queue = [] end def push(item) @queue.push(item) end def pop @queue.shift end end q = Queue.new q.push(:a) :a
  23. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Queue: #push

    and #shift class Queue def initialize @queue = [] end def push(item) @queue.push(item) end def pop @queue.shift end end q = Queue.new q.push(:a) q.push(:b) :a :b
  24. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Queue: #push

    and #shift class Queue def initialize @queue = [] end def push(item) @queue.push(item) end def pop @queue.shift end end q = Queue.new q.push(:a) q.push(:b) q.push(:c) :a :b :c
  25. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Queue: #push

    and #shift class Queue def initialize @queue = [] end def push(item) @queue.push(item) end def pop @queue.shift end end q = Queue.new q.push(:a) q.push(:b) q.push(:c) q.pop #=> :a :b :c
  26. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Queue: #push

    and #shift class Queue def initialize @queue = [] end def push(item) @queue.push(item) end def pop @queue.shift end end q = Queue.new q.push(:a) q.push(:b) q.push(:c) q.pop #=> :a q.pop #=> :b :c
  27. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Queue: #push

    and #shift class Queue def initialize @queue = [] end def push(item) @queue.push(item) end def pop @queue.shift end end q = Queue.new q.push(:a) q.push(:b) q.push(:c) q.pop #=> :a q.pop #=> :b q.pop #=> :c
  28. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Queue: why

    not #unshift? A B C D E
  29. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Queue: why

    not #unshift? A B C D E B C D E F
  30. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Queue: why

    not #unshift? B C D E F
  31. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Queue: why

    not #unshift? B C D E F
  32. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Queue: why

    not #unshift? A B C D E
  33. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Queue: why

    not #unshift? A B C D
  34. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Queue: why

    not #unshift? A B C D F?
  35. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Queue: why

    not #unshift? F? A B C D
  36. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Queue: why

    not #unshift? F? A B C D
  37. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Queue: why

    not #unshift? F? A B C D
  38. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Queue: why

    not #unshift? A B C D F
  39. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Queue: why

    not #unshift? A B C D F SPACE!!! NO SPACE !
  40. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • A Surprising

    Benchmark require 'benchmark/ips' Benchmark.ips do |x| x.report('Array#unshift') do array = (1..100).to_a 100_000.times { |i| array.unshift(i) } end x.report('Array#push') do array = (1..100).to_a 100_000.times { |i| array.push(i) } end x.compare! end
  41. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • A Surprising

    Benchmark Warming up -------------------------------------- Array#unshift 17.000 i/100ms Array#push 19.000 i/100ms Calculating ------------------------------------- Array#unshift 181.828 (± 6.6%) i/s - 918.000 in 5.076970s Array#push 187.124 (± 8.0%) i/s - 931.000 in 5.011387s Comparison: Array#push: 187.1 i/s Array#unshift: 181.8 i/s - same-ish: difference falls within error " ❓
  42. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • A Moment

    of Gratitude Ufuk Kayserilioglu Peter Zhu Kevin Newton
  43. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • jk lol,

    #unshift is fine
  44. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • jk lol,

    #unshift is fine
  45. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • jk lol,

    #unshift is fine
  46. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • jk lol,

    #unshift is fine
  47. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • jk lol,

    #unshift is fine $
  48. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • talk[2] #=>

    "order and randomness”
  49. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Creating randomness

    array = [1, 2, 3, 4, 5] array.shuffle #=> [5, 1, 4, 3, 2] array.shuffle #=> [1, 3, 5, 4, 2] array.shuffle #=> [5, 3, 2, 4, 1] array.sample #=> 4 array.sample(3) => [5, 2, 1]
  50. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Cleaning up

    array = [2, 5, 6, 7, 10, 3, 1, 4, 8, 9] array.sort #=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] array.sort_by { |i| -i } #=> [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
  51. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Mixing it

    up array = [1, 2, 3] array.combination(2).to_a #=> [[1, 2], [1, 3], [2, 3]] array.permutation(2).to_a #=> [[1, 2], [1, 3], [2, 1], [2, 3], [3, 1], [3, 2]]
  52. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Mixing it

    up array = [1, 2, 3] array.combination(2).to_a #=> [[1, 2], [1, 3], [2, 3]] array.permutation(2).to_a #=> [[1, 2], [1, 3], [2, 1], [2, 3], [3, 1], [3, 2]]
  53. ITEMS = ["chair", "sofa", "bed", "pillow", "cushion", "blanket"] def related_items

    ITEMS.sample(3) end RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Displaying random items ITEM_GROUPS = ITEMS.permutation(3).cycle def related_items_group ITEM_GROUPS.next end
  54. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • talk[3] #=>

    "interpretation"
  55. Array includes Enumerable!

  56. Array includes Enumerable! Iteration #each #each_cons #each_slice Introspection #all? #any?

    #none? #one? Selection #filter/#select #find/#detect #reject Extrapolation #map/#collect #reduce/#inject #each_with_object
  57. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Iteration [1,

    2, 3].each do |int| puts int end # This will print: # 1 # 2 # 3 [1, 2, 3, 4, 5, 6].each_slice(3).to_a => [[1, 2, 3], [4, 5, 6]]
  58. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Introspection [1,

    3, 5].all?(&:odd?) #=> true
  59. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Selection [1,

    2, 3, 4, 5].select { |i| i >= 4 } #=> [4, 5] [1, 2, 3, 4, 5].find { |i| i >= 4 } #=> 4
  60. [1, 2, 3].map { |i| i * 2 } #=>

    [2, 4, 6] ["a", "b", "c"].inject("start") { |accum, str| accum + ' ' + str } #=> "start a b c" RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Extrapolation "start" => "start a" => "start a b" => "start a b c"
  61. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Minimum and

    Maximum array = [2, 5, 6, 7, 10, 3, 1, 4, 8, 9] array.min #=> 1 array.max #=> 10 array.minmax #=> [1, 10]
  62. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Minimum and

    Maximum words = ["the", "quick", "brown", "fox", "jumps", "over", "the", "lazy", "dog"] words.minmax #=> ["brown", "the"]
  63. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Adding it

    All Up array = [2, 5, 6, 7, 10, 3, 1, 4, 8, 9] array.sum #=> 55 array.sum { |i| i ** 2 } #=> 385
  64. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Shopping Cart

    catnip = { name: "catnip", price: 6.99 } milk = { name: "milk", price: 2.49 } hat = { name: "Cat in the Hat hat", price: 15.99 } shopping_cart = [[catnip, 2], [milk, 3], [hat, 1]]
  65. most_common_item = shopping_cart. max_by { |product, quantity| quantity }. first[:name]

    #=> "milk" RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Shopping Cart catnip = { name: "catnip", price: 6.99 } milk = { name: "milk", price: 2.49 } hat = { name: "Cat in the Hat hat", price: 15.99 } shopping_cart = [[catnip, 2], [milk, 3], [hat, 1]] most_expensive_item = shopping_cart. max_by { |product, quantity| product[:price] }. first[:name] #=> "Cat in the Hat hat"
  66. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Shopping Cart

    catnip = { name: "catnip", price: 6.99 } milk = { name: "milk", price: 2.49 } hat = { name: "Cat in the Hat hat", price: 15.99 } shopping_cart = [[catnip, 2], [milk, 3], [hat, 1]] order_total = shopping_cart. sum { |product, quantity| product[:price] * quantity } #=> 37.44
  67. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • talk[4] #=>

    "The Second Dimension”
  68. array_2d = [ [1, 2, 3], [4, 5, 6], [7,

    8, 9], ] RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Arrays as Maps
  69. array_2d.reverse #=> [ # [7, 8, 9], # [4, 5,

    6], # [1, 2, 3] # ] array_2d = [ [1, 2, 3], [4, 5, 6], [7, 8, 9], ] RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Arrays as Maps array_2d.map(&:reverse) #=> [ # [3, 2, 1], # [6, 5, 4], # [9, 8, 7] # ]
  70. array_2d.transpose #=> [ # [1, 4, 7], # [2, 5,

    8], # [3, 6, 9] # ] RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Arrays as Maps array_2d = [ [1, 2, 3], [4, 5, 6], [7, 8, 9], ]
  71. array_2d.transpose #=> [ # [1, 4, 7], # [2, 5,

    8], # [3, 6, 9] # ] RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Arrays as Maps array_2d = [ [1, 2, 3], [4, 5, 6], [7, 8, 9], ] array_2d.transpose.reverse #=> [ # [3, 6, 9], # [2, 5, 8], # [1, 4, 7] # ] array_2d.transpose.map(&:reverse) #=> [ # [7, 4, 1], # [8, 5, 2], # [9, 6, 3] # ]
  72. array_2d.rotate #=> [ # [4, 5, 6], # [7, 8,

    9], # [1, 2, 3] # ] array_2d = [ [1, 2, 3], [4, 5, 6], [7, 8, 9], ] RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Arrays as Maps
  73. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Arrays as

    Maps class PuzzlePiece def initialize(array) @array = array end def rotated(i) piece = @array i.times do piece = piece.transpose.reverse end piece end def orientations (0..3).map { |i| rotated(i) } end end
  74. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • talk[5] #=>

    "Search"
  75. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Autocomplete CAT_BREEDS

    = CatBreed.pluck(:name) user_input = Regexp.escape(params[:breed]) #=> "pe" CAT_BREEDS.grep(Regexp.new(user_input, 'i')) #=> ["European Shorthair", "LaPerm", "Persian", "Peterbald", "Serrade Petit"] CAT_BREEDS.grep(Regexp.new('\b' + user_input, 'i')) #=> ["Persian", "Peterbald", "Serrade Petit"] CAT_BREEDS.grep(Regexp.new('\A' + user_input, 'i')) #=> ["Persian", "Peterbald"]
  76. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Filtering by

    Regexp CAT_BREEDS.grep(/ /) #=> ["American Bobtail", "American Curl", ... "Ukrainian Levkoy", "York Chocolate"] CAT_BREEDS.grep_v(/ /) #=> ["Abyssinian", "Aegean", ... "Thai", "Tonkinese", "Toyger"]
  77. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Finding the

    First array = [
 #<Order date="2020-07-17", items=[...], cost=449>,
 #<Order date="2020-09-21", items=[...], cost=250>,
 #<Order date="2021-01-11", items=[...], cost=140>,
 #<Order date="2021-02-29", items=[...], cost=387>,
 #<Order date="2021-03-04", items=[...], cost=88>,
 #<Order date="2021-06-30", items=[...], cost=154>,
 #<Order date="2021-09-06", items=[...], cost=249>,
 #<Order date="2021-10-05", items=[...], cost=321>
 ]
 array.find { |order| order.date >= "2021-01-01" }
 #=> #<Order date="2021-01-11", items=[...], cost=140>

  78. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Finding the

    First array = [
 #<Order date="2020-07-17", items=[...], cost=449>,
 #<Order date="2020-09-21", items=[...], cost=250>,
 #<Order date="2021-01-11", items=[...], cost=140>,
 #<Order date="2021-02-29", items=[...], cost=387>,
 #<Order date="2021-03-04", items=[...], cost=88>,
 #<Order date="2021-06-30", items=[...], cost=154>,
 #<Order date="2021-09-06", items=[...], cost=249>,
 #<Order date="2021-10-05", items=[...], cost=321>
 ]
 array.find { |order| order.date >= "2021-01-01" }
 #=> #<Order date="2021-01-11", items=[...], cost=140>

  79. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Finding the

    First array = [
 #<Order date="2020-07-17", items=[...], cost=449>,
 #<Order date="2020-09-21", items=[...], cost=250>,
 #<Order date="2021-01-11", items=[...], cost=140>,
 #<Order date="2021-02-29", items=[...], cost=387>,
 #<Order date="2021-03-04", items=[...], cost=88>,
 #<Order date="2021-06-30", items=[...], cost=154>,
 #<Order date="2021-09-06", items=[...], cost=249>,
 #<Order date="2021-10-05", items=[...], cost=321>
 ]
 array.find { |order| order.date >= "2021-01-01" }
 #=> #<Order date="2021-01-11", items=[...], cost=140>

  80. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Finding the

    First array = [
 #<Order date="2020-07-17", items=[...], cost=449>,
 #<Order date="2020-09-21", items=[...], cost=250>,
 #<Order date="2021-01-11", items=[...], cost=140>,
 #<Order date="2021-02-29", items=[...], cost=387>,
 #<Order date="2021-03-04", items=[...], cost=88>,
 #<Order date="2021-06-30", items=[...], cost=154>,
 #<Order date="2021-09-06", items=[...], cost=249>,
 #<Order date="2021-10-05", items=[...], cost=321>
 ]
 array.find { |order| order.date >= "2021-01-01" }
 #=> #<Order date="2021-01-11", items=[...], cost=140>

  81. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Finding the

    First array = [
 #<Order date="2020-07-17", items=[...], cost=449>,
 #<Order date="2020-09-21", items=[...], cost=250>,
 #<Order date="2021-01-11", items=[...], cost=140>,
 #<Order date="2021-02-29", items=[...], cost=387>,
 #<Order date="2021-03-04", items=[...], cost=88>,
 #<Order date="2021-06-30", items=[...], cost=154>,
 #<Order date="2021-09-06", items=[...], cost=249>,
 #<Order date="2021-10-05", items=[...], cost=321>
 ]
 array.find { |order| order.date >= "2021-01-01" }
 #=> #<Order date="2021-01-11", items=[...], cost=140>
 array.bsearch { |order| order.date >= "2021-01-01" }
 #=> #<Order date="2021-01-11", items=[...], cost=140>
  82. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Finding the

    First array = [
 #<Order date="2020-07-17", items=[...], cost=449>,
 #<Order date="2020-09-21", items=[...], cost=250>,
 #<Order date="2021-01-11", items=[...], cost=140>,
 #<Order date="2021-02-29", items=[...], cost=387>,
 #<Order date="2021-03-04", items=[...], cost=88>,
 #<Order date="2021-06-30", items=[...], cost=154>,
 #<Order date="2021-09-06", items=[...], cost=249>,
 #<Order date="2021-10-05", items=[...], cost=321>
 ]
 array.find { |order| order.date >= "2021-01-01" }
 #=> #<Order date="2021-01-11", items=[...], cost=140>
 array.bsearch { |order| order.date >= "2021-01-01" }
 #=> #<Order date="2021-01-11", items=[...], cost=140> true
  83. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Finding the

    First array = [
 #<Order date="2020-07-17", items=[...], cost=449>,
 #<Order date="2020-09-21", items=[...], cost=250>,
 #<Order date="2021-01-11", items=[...], cost=140>,
 #<Order date="2021-02-29", items=[...], cost=387>,
 #<Order date="2021-03-04", items=[...], cost=88>,
 #<Order date="2021-06-30", items=[...], cost=154>,
 #<Order date="2021-09-06", items=[...], cost=249>,
 #<Order date="2021-10-05", items=[...], cost=321>
 ]
 array.find { |order| order.date >= "2021-01-01" }
 #=> #<Order date="2021-01-11", items=[...], cost=140>
 array.bsearch { |order| order.date >= "2021-01-01" }
 #=> #<Order date="2021-01-11", items=[...], cost=140> true false
  84. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Finding the

    First array = [
 #<Order date="2020-07-17", items=[...], cost=449>,
 #<Order date="2020-09-21", items=[...], cost=250>,
 #<Order date="2021-01-11", items=[...], cost=140>,
 #<Order date="2021-02-29", items=[...], cost=387>,
 #<Order date="2021-03-04", items=[...], cost=88>,
 #<Order date="2021-06-30", items=[...], cost=154>,
 #<Order date="2021-09-06", items=[...], cost=249>,
 #<Order date="2021-10-05", items=[...], cost=321>
 ]
 array.find { |order| order.date >= "2021-01-01" }
 #=> #<Order date="2021-01-11", items=[...], cost=140>
 array.bsearch { |order| order.date >= "2021-01-01" }
 #=> #<Order date="2021-01-11", items=[...], cost=140> true false true
  85. array = [
 #<Order date="2020-07-17", items=[...], cost=449>,
 #<Order date="2020-09-21", items=[...],

    cost=250>,
 #<Order date="2021-01-11", items=[...], cost=140>, #<Order date="2021-02-29", items=[...], cost=387>,
 #<Order date="2021-03-04", items=[...], cost=88>,
 #<Order date="2021-06-30", items=[...], cost=154>,
 #<Order date="2021-09-06", items=[...], cost=249>,
 #<Order date="2021-10-05", items=[...], cost=321>
 ]
 index = array.bsearch_index { |order| order.date >= "2021-01-01" } #=> 3 array[index..-1] #=> [#<Order date="2021-01-11", items=[...], cost=140>,…] RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Finding the First }
  86. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • talk[6] #=>

    "Arrays as Sets"
  87. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Arrays as

    Sets array = [1, 1, 2, 2, 3, 3, 3] array.uniq #=> [1, 2, 3] array - [2, 3] #=> [1, 1]
  88. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Arrays as

    Sets set1 = [1, 2, 3] set2 = [2, 3, 4, 5] set1 | set2 #=> [1, 2, 3, 4, 5] set1 & set2 #=> [2, 3]
  89. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Arrays as

    Sets author.posts.replace(new_posts_array) # under the hood, performs a diff # let current_posts = author's current posts reload(current_posts & new_posts_array) delete(current_posts - new_posts_array) insert(new_posts_array - current_posts)
  90. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • •Arrays are

    indexed collections of elements •Randomize and sort •Iterate/Interpret one-by-one or together •2D arrays can be used as maps •Rudimentary search capabilities •Set-like functionality What have we covered?
  91. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • talk[7] #=>

    “CatWalk"
  92. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Random Map

    map_items = [:%] * 200 + [:&] * 4 + [:'] * 4 + [:(] * 2 + [')', '*', '+', ','] SIDE_SIZE = 25 map = SIDE_SIZE.times. map { map_items.sample(SIDE_SIZE) } map_items = [:%] * 200 + [:&] * 4 + [:'] * 4 + [:(] * 2 + [')', '*', '+', ',']
  93. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Random Map

    [ [:% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :' , :% , :% , :% , :& , :% , :% ], [:% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% ], [:% , :% , :% , :% , :& , :( , :% , :% , :% , :% , :% , :% , :, , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% ], [:% , :% , :& , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :+ , :% , :% , :% , :% , :% , :% , :% , :% , :% ], [:% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :' , :% , :% , :) , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% ], [:% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :, , :% , :* , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% ], [:% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :' , :% , :% , :( , :* , :% , :) ], [:% , :% , :% , :% , :% , :% , :' , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% ], [:% , :% , :% , :% , :' , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% ], [:% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% ], [:% , :* , :% , :% , :% , :% , :% , :% , :( , :% , :% , :% , :% , :% , :% , :% , :& , :% , :% , :% , :% , :% , :% , :% , :% ], [:% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :& , :% , :) , :% , :% , :% , :% , :% ], [:% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :, , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% ], [:% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :& , :% , :% , :% , :% , :% , :% , :% , :& ], [:% , :, , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% ], [:+ , :% , :% , :% , :% , :& , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :( , :' , :% , :% , :% , :% , :% ], [:% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :+ , :( , :% , :% , :% , :% ], [:% , :% , :% , :% , :% , :% , :' , :% , :% , :% , :% , :% , :% , :' , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% ], [:% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :' , :% , :' , :% , :% , :% , :% , :% , :% , :% , :% ], [:% , :% , :' , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% ], [:% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :' , :% , :% , :% , :% , :% , :% , :% , :% , :% ], [:% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :( , :% , :% , :% , :% , :% , :% , :% , :% , :% ], [:% , :' , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :' , :% , :% ], [:% , :% , :% , :% , :% , :% , :% , :% , :% , :( , :% , :% , :% , :% , :% , :% , :% , :% , :' , :% , :% , :% , :% , :% , :% ], [:% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :( , :% , :% , :% ] ]
  94. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Map Shuffling

    , state[:map] = state[:map]. flatten. shuffle. each_slice(SIDE_SIZE). to_a
  95. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Map Shuffling

    , map = [ [1, 2, 3], [4, 5, 6], [7, 8, 9] ] map.flatten #=> [1, 2, 3, 4, 5, 6, 7, 8, 9] .shuffle #=> [4, 9, 7, 6, 8, 1, 5, 3, 2] .each_slice(3).to_a #=> [ # [4, 9, 7], # [6, 8, 1], # [5, 3, 2] # ]
  96. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Map Movement

    case current_symbol when :& state[:map] = state[:map].transpose.map(&:reverse) else state[:map].each { |line| line.rotate!(-1) } end
  97. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Controls #

    move up = move the map down state[:map].rotate!(-1) # move down = move the map up state[:map].rotate!(1)
  98. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Tracking Active

    Items # Poor performance as array grows def active_items(temp_items) temp_items.select(&:active?) end
  99. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Tracking Active

    Items def active_items(temp_items) current_temp_item_index = temp_items.bsearch_index(&:active?) temp_items[current_temp_item_index..-1] end
  100. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Tracking Active

    Items def active_items(temp_items) current_temp_item_index = temp_items.bsearch_index(&:active?) temp_items[current_temp_item_index..-1] end ) * * + ) * * + , ) ,
  101. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Tracking Active

    Items def active_items(temp_items) current_temp_item_index = temp_items.bsearch_index(&:active?) temp_items[current_temp_item_index..-1] end ) * * + ) * * + , ) ,
  102. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Tracking Active

    Items def active_items(temp_items) current_temp_item_index = temp_items.bsearch_index(&:active?) temp_items[current_temp_item_index..-1] end ) * * + ) * * + , ) , -
  103. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Tracking Active

    Items def active_items(temp_items) current_temp_item_index = temp_items.bsearch_index(&:active?) temp_items[current_temp_item_index..-1] end ) * * + ) * * + , ) , -
  104. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Tracking Active

    Items def active_items(temp_items) current_temp_item_index = temp_items.bsearch_index(&:active?) temp_items[current_temp_item_index..-1] end ) * * + ) * * + , ) , - .
  105. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Tracking Active

    Items def active_items(temp_items) current_temp_item_index = temp_items.bsearch_index(&:active?) temp_items[current_temp_item_index..-1] end ) * * + ) * * + , ) , - .
  106. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Tracking Active

    Items def active_items(temp_items) current_temp_item_index = temp_items.bsearch_index(&:active?) temp_items[current_temp_item_index..-1] end ) * * + ) * * + , ) , - . .
  107. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Tracking Active

    Items def active_items(temp_items) current_temp_item_index = temp_items.bsearch_index(&:active?) temp_items[current_temp_item_index..-1] end ) * * + ) * * + , ) , - . .
  108. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Tracking Active

    Items def active_items(temp_items) current_temp_item_index = temp_items.bsearch_index(&:active?) temp_items[current_temp_item_index..-1].select(&:active?) end
  109. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Tracking Active

    Items def active_items(temp_items) current_temp_item_index = temp_items.bsearch_index(&:active?) temp_items[current_temp_item_index..-1].select(&:active?) end * + * + , ) ,
  110. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Tracking Active

    Items def active_items(temp_items) current_temp_item_index = temp_items.bsearch_index(&:active?) temp_items[current_temp_item_index..-1].select(&:active?) end * + * + , ) ,
  111. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Tracking Active

    Items def active_items(temp_items) current_temp_item_index = temp_items.bsearch_index(&:active?) temp_items[current_temp_item_index..-1].select(&:active?) end * + * + , ) , .
  112. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Tracking Active

    Items def active_items(temp_items) current_temp_item_index = temp_items.bsearch_index(&:active?) temp_items[current_temp_item_index..-1].select(&:active?) end * + * + , ) , .
  113. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Tracking Active

    Items def active_items(temp_items) current_temp_item_index = temp_items.bsearch_index(&:active?) temp_items[current_temp_item_index..-1].select(&:active?) end * + * + , ) , - .
  114. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Tracking Active

    Items def active_items(temp_items) current_temp_item_index = temp_items.bsearch_index(&:active?) temp_items[current_temp_item_index..-1].select(&:active?) end * + * + , ) , - .
  115. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Tracking Active

    Items def active_items(temp_items) current_temp_item_index = temp_items.bsearch_index(&:active?) temp_items[current_temp_item_index..-1].select(&:active?) end * + * + , ) , - . .
  116. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Tracking Active

    Items def active_items(temp_items) current_temp_item_index = temp_items.bsearch_index(&:active?) temp_items[current_temp_item_index..-1].select(&:active?) end * + * + , ) , - . .
  117. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Tracking Active

    Items def active_items(temp_items) current_temp_item_index = temp_items.bsearch_index(&:active?) temp_items[current_temp_item_index..-1].select(&:active?) end * + * + , ) , - . .
  118. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Tracking Active

    Items def active_items(temp_items:, **) earliest_active_start_time = Time.now - Item::MAX_DURATION current_temp_item_index = temp_items.bsearch_index { |i| i.start_time > earliest_active_start_time } temp_items[current_temp_item_index..-1].select(&:active?) end
  119. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • •Multiplicative items

    implemented with #inject •Cheat codes use a queue-based keylogger •Final score uses #tally CatWalk Miscellany
  120. https://github.com/amcaplan/catwalk

  121. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Appreciation Circle

    array = %w(Alex Ariel Daniel Erez Ira Omer Oren) array.shuffle.cycle.each_cons(2).first(array.size).to_h #=> { # "Erez"=>"Omer", # "Omer"=>"Ira", # "Ira"=>"Alex", # "Alex"=>"Oren", # "Oren"=>"Ariel", # "Ariel"=>"Daniel", # "Daniel"=>"Erez" # }
  122. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Please say

    hi in Discord / real life!