2015-01-30 3 views
0

В настоящее время я изучаю Ruby и для обучения. Я хотел расширить класс Array с помощью собственного метода, который проверяет массив на определенное значение и возвращает его индекс. Если значение имеет более одного индекса в массиве, то верните все индексы.Поиск индекса значения в массиве

Я попытался решить эту проблему с помощью некоторых циклов и некоторых реляционных операторов, но мне не очень нравится работать с классом массива. Если бы кто-нибудь мог дать мне решение для этого квеста, на котором я мог бы ориентироваться, это было бы здорово.

+0

Вы должны опубликовать код, который показывает, что вы пробовали. –

+0

Большинство методов, которые помогут в этом, находятся в модуле Enumerable (а массивы перечислены). –

+0

Этот вопрос вполне может стать закрытым. Надеюсь нет. Прочитайте рекомендации по [как спросить] (http://stackoverflow.com/help/how-to-ask) и предоставьте код, который вы укажете, где вы «пытались решить эту проблему», чтобы вы могли получить обратную связь, которая имеет отношение к вашему вопросу, и помочь другим, находящимся в вашей ситуации. – vgoff

ответ

1

Вот один из способов среди многих:

class Array 
    def find_indices(val) 
    each_with_index.select { |e,i| e == val }.map(&:last) 
    end 
end 

[1,3,5,2,6,3,5,7,8,3,2,4].find_indices(3) 
    #=> [1, 5, 9] 

Вот что происходит. Сначала val устанавливается равным 3. Затем метод Enumerable#each_with_index отправляется на номер self, поскольку не предоставляется явный приемник. self равно массив, который вы можете легко подтвердить, добавив строку:

puts "self = #{self}" 

к началу метода find_indices. Теперь вы получите:

[1,3,5,2,6,3,5,7,8,3,2,4].find_indices(3) 
# self = [1, 3, 5, 2, 6, 3, 5, 7, 8, 3, 2, 4] 
#=> [1, 5, 9] 

Как видно из документации, так как each_with_index не дается блок, перечислитель возвращается:

enum = [1,3,5,2,6,3,5,7,8,3,2,4].each_with_index 
    #=> #<Enumerator: [1, 3, 5, 2, 6, 3, 5, 7, 8, 3, 2, 4]:each_with_index> 

Чтобы проверить элементы enum, преобразовать его в массив:

enum.to_a 
    #=> [[1, 0], [3, 1], [5, 2], [2, 3], [6, 4], [3, 5], 
    # [5, 6], [7, 7], [8, 8], [3, 9], [2, 10], [4, 11]] 

Далее мы посылаем метод Enumerable#select к enum:

new_enum = enum.select 
    #=> #<Enumerator: #<Enumerator: [1, 3, 5, 2, 6, 3, 5, 7, 
    # 8, 3, 2, 4]:each_with_index>:select> 

new_enum.to_a 
    #=> [[1, 0], [3, 1], [5, 2], [2, 3], [6, 4], [3, 5], 
    # [5, 6], [7, 7], [8, 8], [3, 9], [2, 10], [4, 11]] 

Обратите внимание на описание new_enum. Вы можете счесть это соображением как «составной перечислитель», но это перечислитель.

Теперь мы даем select блок, поэтому каждый элемент new_enum будет передан блоку. Первый элемент передается в [1, 0] и назначение блоков переменных производится:

e, i = [1, 0] 
e #=> 1 
i #=> 0 

Мы находим, что (e == val) #=> (1 == 3) #=> false, поэтому элемент не выбран. Следующий элемент, переданный блоку, [3, 1], вызывает (3 == 3) #=> true, поэтому выбирается [3, 1].

Получаем:

a = new_enum.each { |e,i| e == val } 
    #=> [[3, 1], [3, 5], [3, 9]] 

Как это индексы для этих значений, которые мы хотим, мы извлекая их отображения:

a.map(&:last) 
    #=> [1, 5, 9] 

что эквивалентно:

a.map { |e| e.last } 

Эта последняя операция также может быть выполнена таким образом:

a.transpose.last 

Еще один простой способ сделать это следующим образом.

class Array 
    def find_indices(val) 
    index = 0 
    each_with_object([]) do |e,a| 
     (a << index) if e == val 
     index += 1 
    end 
    end 
end 

[1,3,5,2,6,3,5,7,8,3,2,4].find_indices(3) 
    #=> [1, 5, 9]