each_cons in Ruby on Rails: from simple to real-life examples

The each_cons method in Ruby on Rails is a versatile tool that simplifies iterating over consecutive pairs in a collection. With just a single line of code, we can perform tasks such as finding patterns or calculating differences between adjacent elements. In this blog post, we’ll explore the various use cases of each_cons, starting from simple examples and gradually progressing to more complex ones.

Simple Example: let’s start with a basic example using an array of numbers. Here, each_cons(2) iterates over consecutive pairs within the numbers array. The variable pair receives an array containing two adjacent elements on each iteration.

1
2
3
4
5
6
7
8
9
10
11
numbers = [1, 2, 3, 4, 5]

numbers.each_cons(2) do |pair|
  puts "Pair: #{pair}"
  # Additional logic to manipulate the pair
end

#=> Pair: [1, 2]
#=> Pair: [2, 3]
#=> Pair: [3, 4]
#=> Pair: [4, 5]

Finding Patterns: each_cons is handy for identifying patterns in a sequence. Here, each_cons(3) iterates over consecutive triples of characters in the text string.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
text = "Hello, world!"

text.chars.each_cons(3) do |triple|
  puts "Triple: #{triple.join}"
  # Additional logic to analyze the triple
end

#=> Triple: Hel
#=> Triple: ell
#=> Triple: llo
#=> Triple: lo,
#=> Triple: o, 
#=> Triple: , w
#=> Triple:  wo
#=> Triple: wor
#=> Triple: orl
#=> Triple: rld
#=> Triple: ld!

In this example, we use each_cons(2) to iterate over consecutive pairs of words in the words array. The max_by method is used to find the pair with the maximum difference in length. In this case, the longest consecutive sequence is between elephant and frog.

1
2
3
4
5
6
7
words = ["apple", "banana", "cat", "dog", "elephant", "frog", "giraffe"]

longest_sequence = words.each_cons(2).max_by { |w1, w2| w2.length - w1.length }

puts "Longest consecutive sequence: #{longest_sequence}"

#=> Longest consecutive sequence: ["elephant", "frog"]

Calculating Prices Differences: each_cons is also useful for calculating differences between adjacent elements. In this example, each_cons(2) is combined with map to calculate the differences between consecutive elements in the prices array.

1
2
3
4
5
6
7
prices = [10.5, 12.3, 11.8, 14.2, 13.5]

differences = prices.each_cons(2).map { |pair| pair[1] - pair[0] }

puts "Price differences: #{differences}"

#=> Price differences: [1.8, -0.5, 2.4, -0.7]

Adding Numbers: In this example, we use each_cons(2) to iterate over consecutive pairs of numbers in the numbers array. The map method calculates the sum of each pair, resulting in the array [4, 8, 12, 16].

1
2
3
4
5
6
7
numbers = [1, 3, 5, 7, 9]

sums = numbers.each_cons(2).map { |n1, n2| n1 + n2 }

puts "Pair sums: #{sums}"

#=> Pair sums: [4, 8, 12, 16]

Advanced Analysis: each_cons can handle more complex scenarios, such as analyzing sequences of objects. Considering an array of hashes, each_cons(3) iterates over consecutive triples of hashes in the data array. We calculate the average value of each triple based on the value attribute and print it to the console.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
data = [
  { id: 1, value: 10 },
  { id: 2, value: 15 },
  { id: 3, value: 12 },
  { id: 4, value: 20 }
]

data.each_cons(3) do |triple|
  average = triple.sum { |hash| hash[:value] } / triple.size.to_f
  puts "Triple average: #{average}"
end

#=> Triple average: 12.333333333333334
#=> Triple average: 15.666666666666666
#=> Triple average: 15.666666666666666

Stock Market Analysis: suppose you have an array of stock prices representing the closing prices of a stock over several days. You can use each_cons to calculate the percentage change between consecutive closing prices, allowing you to analyze the volatility of the stock.

1
2
3
4
5
6
7
prices = [100.5, 102.3, 98.7, 105.2, 99.8, 101.4, 98.2]

percentage_changes = prices.each_cons(2).map { |p1, p2| ((p2 - p1) / p1) * 100 }

puts "Percentage changes: #{percentage_changes}"

#=> Percentage changes: [1.791044776119407, -3.5114503816793835, 6.595744680851055, -5.13245033112583, 1.603206412825632, -3.1653439153439157]

Fitness Tracker: imagine you have an array of daily step counts representing a person’s activity levels. You can use each_cons to identify streaks of consecutive days where the person achieved a certain step count goal, helping track their consistency.

1
2
3
4
5
6
7
step_counts = [5000, 6000, 7500, 8000, 4000, 9000, 9500, 10000, 11000]

goal_streaks = step_counts.each_cons(3).select { |counts| counts.all? { |count| count >= 8000 } }

puts "Goal streaks: #{goal_streaks}"

#=> Goal streaks: [[8000, 9000, 9500], [9000, 9500, 10000], [9500, 10000, 11000]]

Time Series Analysis: suppose you have an array of temperature measurements taken at regular intervals throughout the day. You can use each_cons to identify patterns or anomalies by comparing consecutive temperature values.

1
2
3
4
5
6
7
temperatures = [25.2, 25.5, 25.8, 26.1, 25.9, 26.3, 26.0, 25.7]

anomalies = temperatures.each_cons(4).select { |temps| temps.max - temps.min > 0.5 }

puts "Temperature anomalies: #{anomalies}"

#=> Temperature anomalies: [[25.2, 25.5, 25.8, 26.1], [25.9, 26.3, 26.0, 25.7]]