2016-02-26 2 views
1

У меня есть массив массивов:Нахождение индекса элементов в массиве массивов

[ 
    [0,0,0,0], 
    [0,1,0,0], 
    [0,0,0,1], 
    [0,0,0,0] 
] 

Я хочу найти индекс (строки и столбца) из элементов со значением 1. Как я могу это сделать? Мне нужны эти значения, чтобы я мог манипулировать ячейками по обе стороны от 1. Я посмотрел на метод find.index, но я не уверен.

+0

Интересно, почему люди продолжают использовать вложенный массив для таких ситуаций. Плоский массив намного легче справиться. – sawa

+1

Когда вы приводите пример, назначьте переменную каждому входному объекту. Таким образом, переменная может ссылаться на ответы и комментарии. Все, кроме одного ответа, начинаются с определения массива. Если бы вы написали 'arr = [[0,0 ....]]' ничто из этого не понадобилось - ответы просто написали бы 'arr'. Я понимаю, что вы новичок в SO. Это всего лишь совет, а не критика. –

ответ

2
a = [ 
    [0,0,0,0], 
    [0,1,0,0], 
    [0,0,0,1], 
    [0,0,0,0] 
].flatten 

a.each.with_index.select{|e, _| e == 1}.map{|_, i| i.divmod(4)} 
# => [[1, 1], [2, 3]] 

Следует понимать как (строка 1, столбец 1) и (строка 2, столбец 3).

+0

Любой шанс избавиться от этого жестко закодированного «4»? ;-) – Stefan

+1

@Stefan Можно получить '4' как длину первого элемента исходного массива, но мое предложение состоит в том, чтобы иметь плоский массив с самого начала, с дополнительной информацией' 4'. – sawa

+1

Либо это, либо хэш с парами '[x, y] => value' – Stefan

0

Ruby имеет очень гибкий функциональный модуль Enumerable, который входит во многие стандартные коллекции (массивы, хэши, наборы). Вы можете найти документацию at ruby-doc.org.

Хороший один вкладыш решить эту проблему в максимально #rows * 2 #columns время будет следующее:

matrix 
    .each.with_index 
    .inject([]) { |acc, (el,idx)| el.include?(1) ? acc.push([idx, el.index(1)]) : acc } 
# => [[1,1],[2,3]] 
+1

Это не работает, если строка содержит более одного' 1' – Stefan

0
z = [ 
    [0,0,0,0], 
    [0,1,0,0], 
    [0,0,0,1], 
    [0,0,0,0] 
] 

Во-первых, давайте найти соответствующие строки:

rows = z.each_with_index.select { |row, index| row.include? 1}.map(&:last) 
# => [1, 2] 

И затем для каждой строки найдем индекс соответствия 1:

cols = rows.map {|row| z[row].each_with_index.select { |item, index| item == 1}.map(&:last) } 
# => [[1], [3]] 

Если мы хотим, мы можем затем объединить их с помощью zip:

rows.zip(cols) 
# => [[1, [1]], [2, [3]]] 

выше работает, даже если ряд z содержит несколько вхождений 1

Например, если у нас было:

z = [ 
    [1,0,0,1], 
    [0,1,0,0], 
    [0,0,0,1], 
    [1,1,1,0] 
] 

затем

rows = z.each_with_index.select { |row, index| row.include? 1}.map(&:last) 
# => [0, 1, 2, 3] 
cols = rows.map {|row| z[row].each_with_index.select { |item, index| item == 1}.map(&:last) } 
# => [[0, 3], [1], [3], [0, 1, 2]] 
rows.zip(cols) 
# => [[0, [0, 3]], [1, [1]], [2, [3]], [3, [0, 1, 2]]] 
+0

Хорошая точка для неявного указания недостатка в ответе Тимона Вонка. – sawa

3

Не то фантазии, но вы могли бы использовать две петли:

ary = [ 
    [0, 0, 0, 0], 
    [0, 1, 0, 0], 
    [0, 0, 0, 1], 
    [0, 0, 0, 0] 
] 

result = [] 
ary.each_with_index do |row, i| 
    row.each_with_index do |value, j| 
    result << [i, j] if value == 1 
    end 
end 
result 
#=> [[1, 1], [2, 3]] 
+1

... или 'ary.each_index {| i | ary.first.each_index {| j | результат << [i, j], если ary [i] [j] == 1}} '. –

1

Рассмотрите возможность использования Matrix класса.

require 'matrix' 

arr = [ 
    [0, 0, 0, 0], 
    [0, 1, 0, 0], 
    [0, 0, 0, 1], 
    [0, 0, 0, 0] 
]  

target = 1 

Matrix[*arr].each_with_index.with_object([]) { |(e,row,col),a| 
    a << [row,col] if e==target } 
    #=> [[1, 1], [2, 3]] 

Мне нравится, как это читается.

+0

Спасибо за вашу помощь. – VixB

+0

Также будет работать комбинация 'select' и' map': 'm.each_with_index.select {| e, r, c | e == 1} .map {| e, r, c | [r, c]} ' – Stefan

Смежные вопросы