Aparichith
Aparichith

Reputation: 1535

Ruby index of array elements

Consider I have an array of integer elements. In which I am trying to find the index where a long sequence of repetitive numbers begins.

my_array = [100, 101, 100, 102, 100, 100, 101, 100, 250, 251, 253, 260, 250, 200, 100, 100, 100, 100, 100, 100, 100, 100, 100, 120]

Bellow is the way I am trying to find the index. Can anyone suggest me more optimised and correct way of doing it?

my_array.each with_index do |e, x|
  match = e.to_s * 5
  next_10 = my_array[x + 1, 5].join()

  if match == next_10
    puts "index #{x}"
    break
  end
end

#index 14

Upvotes: 3

Views: 1129

Answers (4)

Oshan Wisumperuma
Oshan Wisumperuma

Reputation: 1958

my_array = [100, 101, 100, 102, 100, 100, 101, 100, 250, 251, 253, 260, 250, 200, 100, 100, 100, 100, 100, 100, 100, 100, 100, 120]


index_and_repetitions = lambda { |my_array|
  stk = {}
  previous = my_array[0]
  last_index = 0
  stk[last_index] = 1
  my_array.drop(0).each_with_index{|item, index|
    if item == previous
      stk[last_index] += 1
    else
      last_index = index
      stk[last_index] = 1
      previous = item
    end
  }
  stk
}

stk = index_and_repetitions.call(my_array)
puts stk.key(stk.values.max)

you can find benchmark results(compared to others answers) from here.

Upvotes: 1

Cary Swoveland
Cary Swoveland

Reputation: 110755

I assume the objective is to find the index of the first element of the longest sequence of equal elements in the given array.

my_array = [100, 101, 100, 102, 100, 100, 101, 100, 250, 251, 253, 260, 250, 200,
            100, 100, 100, 100, 100, 100, 100, 100, 100,
            120]

Here that would be 14, the index of 100 that is followed by 8 more 100's.

We can do that as follows.

my_array.each_index.chunk { |i| my_array[i] }.
         max_by { |_,a| a.size }.
         last.
         first
           #=> 14

The steps are as follows.

enum0 = my_array.each_index
  #=> #<Enumerator: [100, 101, 100,..., 100, 120]:each_index> 

We can see the elements that will be generated by this enumerator by converting it to an array.

enum0.to_a
  #=> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
  #    17, 18, 19, 20, 21, 22, 23]

Continuing,

enum1 = enum0.chunk { |i| my_array[i] }
  #=> #<Enumerator: #<Enumerator::Generator:0x000058d8d09ec8a0>:each> 

In view of the above expression's return value, enum1 could be thought of as a compound enumerator, though Ruby has no such concept. Let's see the values enum1 will generate.

enum1.to_a
  #=> [[100, [0]], [101, [1]], [100, [2]], [102, [3]], [100, [4, 5]],
  #    [101, [6]], [100, [7]], [250, [8]], [251, [9]], [253, [10]],
  #    [260, [11]], [250, [12]], [200, [13]],
  #    [100, [14, 15, 16, 17, 18, 19, 20, 21, 22]],
  #    [120, [23]]]

Continuing,

a = enum1.max_by { |v,a| a.size }
  #=> [100, [14, 15, 16, 17, 18, 19, 20, 21, 22]]

As v is not used in the block, this expression would customarily be written:

a = enum1.max_by { |_,a| a.size }

The presence of the underscore (a valid local variable) signals to the reader that that block variable is not used in the block calculation. The last two steps are as follows.

b = a.last
  #=> [14, 15, 16, 17, 18, 19, 20, 21, 22] 
b.first
  #=> 14 

See Enumerable#chunk and Enumerable#max_by.

Upvotes: 1

ray
ray

Reputation: 5552

In first iteration, I am getting array of repeating elements sequence and then I proceed further with logic,

groups = my_array[1..-1].inject([[my_array[0]]]) { |m, n| m.last[0] == n ? m.last << n : m << [n]; m }
# => [[100], [101], [100], [102], [100, 100], [101], [100], [250], [251], [253], [260], [250], [200], [100, 100, 100, 100, 100, 100, 100, 100, 100], [120]]

groups[0,groups.index(groups.sort { |a,b| a.count <=> b.count }.last)].flatten.count
# => 14

Using regex, it can be precise and simple.

Upvotes: 1

Pengcheng Zhou
Pengcheng Zhou

Reputation: 172

my_array.index.with_index{|value,index| my_array[index,6].uniq.size==1}

This is a kind of tweak, if you mean "optimised" just in the way code looks like.If you mean optimised performance. it does not fit.

Upvotes: 2

Related Questions