2013-05-22 5 views
1

Мне нужно написать метод group_by самостоятельно. Это то, что у меня есть до сих пор:Напишите метод group_by самостоятельно

module Enumerable 
    def group_by(&b) 
    solution = {} 
    self.each {|key,val| 
     b.call(var) 
     solution = { key=> (val) } 
    } 
    end 
end 

ary = [1,2,3,4,5,6,7,8,9,10] 

p ary.group_by() { |i| i%3 } 

Я не понимаю. Я надеюсь, что вы можете мне помочь.

+0

Привет - вам кажется, что здесь новый. Это действительно помогает нам помочь вам, если вы включите сообщение об ошибке, которое вы получите при попытке запустить ваш код. Сейчас нам очень сложно рассказать, что вы на самом деле просите нас *. «Я этого не понимаю» вовсе не сужает это. Поэтому вы просите нас угадать, что вам нужно, а не просто говорить нам. В будущем - можете ли вы, пожалуйста, дать нам более подробную информацию по вашему вопросу? Это действительно поможет нам помочь вам лучше (это означает, что ваш вопрос будет отвечать быстрее). –

ответ

3

Я не совсем уверен, как я могу помочь, кроме публикации решения, но может быть, какое-то описание с тем, что вам трудно найти?

Несколько вопросов я заметил:

  • Вы используете мимо двух аргументов в блоке, когда массив имеет только 1, значение
  • вы вызываете блок с var, который не существует в текущем scope, может быть, вы имели в виду val?
  • вы не проверить, если что-то уже существует в новом словаре решения
  • перезаписываются словарь SOLUTION каждый раз, когда вы перебираете новое значение в массиве

Вот что я придумал:

module Enumerable 

    def group_by 
    solution = {} 
    each do |value| 
     key = yield value 
     if solution.key?(key) 
     solution[key] << value 
     else 
     solution[key] = [value] 
     end 
    end 
    solution 
    end 

end 

ary = [1, 2, 3, 4, 5] 
p ary.group_by { |i| i % 3 } 

выход:

{1=>[1, 4], 2=>[2, 5], 0=>[3]} 

вы можете сп eck, если блок был предоставлен, если кто-то пытается использовать эту функцию неправильно, подумайте об использовании инструкции unless block_given?, но, возможно, вы можете попробовать реализовать это самостоятельно.

+0

Taht идеально, именно то, что мне нужно. Просто для понимания.«key = yield value» выполняет итерацию каждого значения и помещает их в переменную «ключ»? и что именно является решением.key? (ключ)? – user2409416

+0

@ user2409416 'key? (Key) → Возвращает true, если данный ключ присутствует в hash.' и' key = yield value' вызывает блок со значением для получения ключа (чтобы сгруппировать словарь), чтобы вы могли см. добавление значения в словарь с помощью этого ключа. –

+0

Хорошее решение. Вы должны вернуть «Перечислитель», если не указано ни одного блока. –

3
module Enumerable 
    def group_by &b; inject({}){|h, e| (h[b.call(e)] ||= []).push(e); h} end 
end 

[1,2,3,4,5,6,7,8,9,10].group_by{|i| i % 3} 
# => {1 => [1, 4, 7, 10], 2 => [2, 5, 8], 0 => [3, 6, 9]} 
+2

«Умное» решение, меньшее, чем мое, но не слишком уверенное, если его легко понять для начинающего пользователя. Голосуйте за приятность! –

+0

Выглядит неплохо, но я думаю, что мой проф. не верю мне, что я написал это:/ – user2409416

+0

Нет, я стоун! Я спросил, потому что я хочу понять, что я делаю, и первое решение поможет мне больше, но, конечно, ваше решение хорошо сделано ... вот и все, что я хотел сказать. - « – user2409416

2

Другим решение для сравнения:

module Enumerable 
    def group_by 
    {}.tap do |group| 
     each{ |value| (group[ yield(value) ] ||= []) << value } 
    end 
    end 
end 
  • использует tap, чтобы избежать неприглядной картины

    thing = {} 
    # do stuff with thing 
    thing # return it 
    
  • использует ||= для создания новой коллекции массива уже нет

В качестве альтернативы:

module Enumerable 
    def group_by 
    Hash.new{ |h,k| h[k]=[] }.tap do |group| 
     each{ |value| group[ yield(value) ] << value } 
     group.default = nil # remove the default_proc when done 
    end 
    end 
end 
+1

Вы, кажется, Мне понравилось, что я использовал некоторые из них от вас давным-давно. – sawa

+0

@sawa Я действительно знаю, что некоторые нахмурились, используя его для этого шаблона, предпочитая 'each_with_object', но это еще и типизация и (крошечный бит) медленнее. – Phrogz

+0

Мне нравится ваш стиль лучше. Это концептуально более естественно, поскольку исходный ресивер - это то, что выходит (модифицировано) как выход. – sawa

2

С моей backports gem:

module Enumerable 
    def group_by 
    return to_enum(:group_by) unless block_given? 
    result = {} 
    each do |o| 
     key = yield(o) 
     ary = result.fetch(key){ result[key] = [] } 
     ary << o 
    end 
    result 
    end 
end 

В отличие от всех решений, представленных до сих пор, она проходит RubySpec.

+2

Когда я вижу лицо Марка-Андре, я просто упрекаю, не читая :-) –

+0

Могу я просто попросить вас сказать что-нибудь о вашем более плотном стиле кода? Как в 'fetch (yield (o)) {| key | ... []} '. У вас нет проблем с чтением его после себя? (Я бы написал это с большим количеством пробелов ...) Это вопрос личных предпочтений, или просто я недостаточно приправлен? Кроме того, могу ли я спросить, трудно ли проверить, проходит ли что-то RubySpec? –

+0

@BorisStitnicky Это правда, что эта линия была довольно компактной и не читаемой. Я отредактировал свой ответ, я думаю, теперь это более читаемо. –

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