2017-01-20 4 views
1

Я хотел бы отфильтровать 2-мерный массив, содержащий требуемые индексы столбца, и вернуть 2d-массив только с этими столбцами. За исключением пустого массива, я хотел бы вернуть тот же 2-мерный массив.Фильтрация 2-мерной матрицы без побочных эффектов

Также я не хочу изменять исходный массив, и я бы хотел написать свой код без каких-либо операторов if или ограничить разветвление как можно больше.

Мне интересно, является ли оно избыточным Marshal#load и Marshal#dump и использовать #map!.

Причина, по которой я решил использовать #map!, так что мне не нужно использовать блок if..else..end, но мне любопытно узнать другие стратегии.

Ниже мое решение:

def keep_columns args 
    matrix = Marshal.load Marshal.dump args[:matrix] 
    columns = args[:columns] 
    matrix.map! do |row| 
    row.select.with_index { |_,idx| columns.include? idx } 
    end unless columns.empty? 
    matrix 
end 

matrix = [['foo','bar', 'baz'],['cats', 'and', 'dogs']] 

keep_columns matrix: matrix, columns: [0,2] 
#=> [["foo", "baz"], ["cats", "dogs"]] 
keep_columns matrix: matrix, columns: [] 
#=> [["foo", "bar", "baz"], ["cats", "and", "dogs"]] 

ответ

1

Попробуйте

matrix.map(&:dup) 

Это создает копию матрицы.


Pro Типпы - Ваш код имеет линейный поиск более columns для каждого элемента внутреннего цикла, возможно, использовать row.values_at(*columns) вместо этого?

def keep_columns(args) 
    columns, matrix = args.values_at(:columns, :matrix) 
    return matrix.map(&:dup) if columns.empty? 
    matrix.map { |row| row.values_at(*columns) } 
end 
+0

+1 для прокрутки, будет повышаться, если у меня есть мои голоса. Можете ли вы привести пример? Кроме того, как вы думаете, ваша техника 'matrix.dup.map (&: dup)' применима к [этому вопросу] (http://stackoverflow.com/questions/41657091/use-replace-to-make-a-copy -of-ан-массив)? – mbigras

+0

Этот вопрос имеет только 1D-массив. Для 2D-массивов 'matrix.map (&: dup)' корректно, ваш код маршаллинга также будет клонировать элементы матрицы, которые вы точно не хотите. – akuhn

+1

Спасибо @akuhn! Можете ли вы изменить '(столбцы)' на '(* columns)'? :) – mbigras

2

Вы можете использовать Array#transpose до и после Hash#values_at.

def extract_columns(arr, columns) 
    return arr if columns.empty? 
    arr.transpose.values_at(*columns).transpose 
end 

arr = [['foo','bar', 'baz'],['cats', 'and', 'dogs']] 

extract_columns(arr, [0, 2]) 
    #=> [["foo", "baz"], ["cats", "dogs"]] 
extract_columns(arr, []) 
    #=> [["foo", "bar", "baz"], ["cats", "and", "dogs"]] 

Отметьте, что arr не изменяется.