2013-09-09 2 views
0

При написании повторяющегося кода с мутацией в рубине, я часто ловлю себя после этой схемы: (. x часто не имеет такую ​​же форму, как some_data, поэтому простой map не будет делать)Есть ли абстракция для шаблона declare-update-return?

def build_x some_data 
    x = [] # or x = {} 
    some_data.each do |data| 
    x.some_in_place_update! (... data ...) 
    end 
    x 
end 

Есть ли более идиоматический или лучший способ написать код, который следует за этим шаблоном?


[править] Реальный пример:

def to_hierarchy stuff 
    h = {} 
    stuff.each do |thing| 
    path = thing.uri.split("/").drop(4) 
    sub_h = h 
    path.each do |segment| 
     sub_h[segment] ||= {} 
     sub_h = sub_h[segment] 
    end 
    sub_h.merge!(
     data: thing.data, 
    ) 
    end 
    h 
end 

Это начинается с плоским списком thing с, которые связаны, но отдельными uri с. Он преобразует этот плоский список в иерархию, группируя связанные thing s, которые имеют одинаковые segment s из uri. Это следует описанному мной шаблону: инициализировать h, перебрать некоторые данные и мутировать h по пути, а затем выплюнуть h в конце.

[edit2] Другой связанный пример

def count_data obj 
    i = if obj[:data] then 1 else 0 
    obj.each do |k, v| 
    i += count_statements v unless :data == k 
    end 
    i 
end 
+0

Непонятно, что вы хотите. 'x = []', за которым следует 'x.some_in_place_update! (data)' делает 'some_in_place_update!' метод 'Array', и его название подразумевает, что он модифицирует массив' x' на месте (если задан элемент 'some_data 'как входной), хотя он пуст. Вы действительно * исправили 'Array' новым методом? Это очень помогло бы узнать, что делает «some_in_place_update!». – Borodin

+0

вы можете использовать один или два примера реальных методов с этим шаблоном? – tessi

+0

@Borodin «на месте обновления», возможно, был плохим способом описания того, что я на самом деле имел в виду. Я пытался передать идею о том, что объект 'x' был мутирован этим вызовом метода. –

ответ

1

Ваш to_hierarchy пример может быть сделано с each_with_object:

def to_hierarchy stuff 
    stuff.each_with_object({}) do |thing, h| 
    #... 
    end 
end 

each_with_object проходит дополнительный объект в блоке и возвращает этот объект, когда итерации готово.

Если вы больше традиционалист, вы могли бы использовать inject:

def to_hierarchy stuff 
    stuff.inject({}) do |h, thing| 
    #... 
    h 
    end 
end 

Обратите внимание на изменение порядка блока аргумент и что блок должен вернуть h так что inject может кормить его обратно в следующий блок призывание.

Ваш общий пример можно записать в виде:

def build_x some_data 
    some_data.each_with_object([]) do |data, x| 
    x.some_in_place_update! (... data ...) 
    end 
end 

или:

def build_x some_data 
    some_data.inject({}) do |x, data| 
    x.some_in_place_update! (... data ...) 
    x 
    end 
end 
1

Ах! Вы хотите each_with_object. Нравится

def to_hierarchy stuff 
    stuff.each_with_object({}) do |thing, h| 
    path = thing.uri.split("/").drop(4) 
    sub_h = h 
    path.each do |segment| 
     sub_h[segment] ||= {} 
     sub_h = sub_h[segment] 
    end 
    sub_h.merge!(
     data: thing.data, 
    ) 
    end 
end 

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

  • Нет связанных вопросов^_^