Решение на Първа задача от Кирил Владимиров

Обратно към всички решения

Към профила на Кирил Владимиров

Резултати

  • 6 точки от тестове
  • 2 бонус точки
  • 8 точки общо
  • 8 успешни тест(а)
  • 0 неуспешни тест(а)

Код

class Integer
def prime_divisors
(2..abs).select { |n| self % n == 0 and ('1' * n) !~ /^1?$|^(11+?)\1+$/ }
end
end
class Range
def fizzbuzz
map do |n|
if n % 15 == 0
:fizzbuzz
elsif n % 3 == 0
:fizz
elsif n % 5 == 0
:buzz
else
n
end
end
end
end
class Hash
def group_values
result = {}
each do |key, value|
result[value] ||= []
result[value] << key
end
result
end
end
class Array
def densities
map { |n| count n }
end
end

Лог от изпълнението

........

Finished in 0.00729 seconds
8 examples, 0 failures

История (5 версии и 12 коментара)

Кирил обнови решението на 14.10.2012 16:19 (преди над 11 години)

+class Integer
+ def prime_divisors
+ (2..self.abs).select { |n| self % n == 0 and ('1' * n) !~ /^1?$|^(11+?)\1+$/ }
+ end
+end
+
+class Range
+ def fizzbuzz
+ self.collect do |n|
+ n = :fizz if n % 3 == 0
+ n = :buzz if n.kind_of? Numeric and n % 5 == 0
+ n = :fizzbuzz if n.kind_of? Numeric and n % 5 == 0 and n % 3 == 0
+ n
+ end
+ end
+end
+
+class Hash
+ def group_values
+ self.inject(Hash.new([])) { |result, item| result[item[1]] += [item[0]]; result }
+ end
+end
+
+class Array
+ def densities
+ self.collect { |n| self.count n }
+ end
+end
  • self. се изпуска максимално много; в случая на теб не ти е необходим никъде и можеш да го изпуснеш навсякъде
  • Проверката за kind_of?е ненужна във fizzbuzz, понеже условието не го изисква; а и е малко излишно да го правиш на всяка итерация, би могъл да провериш begin/end преди началото на map
  • А, и map се ползва по-често като име, отколкото collect
  • Хешът, който връщаш в group_values има страничен ефект — дифолтна стойност; може би не искаш да става така :)
  • Не съм сигурен с какво мога да заменя self. Там ще трябва да почета повече, тъй като и на мен не ми хареса.
  • Проверката kind_of? я използвам, тъй като ако след n = :fizz if n % 3 == 0, n стане символ на следващите две няма оператор % за него и гърми. Много кофти идея ли е да го използвам така?
  • Относно map - мерси, не знаех.
  • Дифолтната стойност я използвам, за да мога свободно да си ползвам операторът +, защото иначе не мога да събера nil с Array. Работата е там, че все още не осъзнавам какъв ми е страничният ефект...

Да, кофти идея е да го ползваш така, понеже създаваш темпорална кохезия между двата реда код - ако ги разменя, има друг ефект. Друго което е кофти, е да не го правиш с elsif или с case. И двете правят кода по-труден за разбиране. Въобще, fizzbuzz-а ти е под критика.

Мда, съгласен съм. Направих го така за да ме одобри skeptic за броя редове в метод(5).

Първоначалната имплементация беше:

  if n % 5 == 0 and n % 3 == 0
    :fizzbuzz
  elsif n % 3 == 0
    :fizz
  elsif n % 5 == 0
    :buzz
  else
    n

Ей сега ме изби на простотия с case, след като ми позволи да си ползвам моя метод:

  case n.prime_divisors.join
    when /35/ then :fizzbuzz
    when /3/ then :fizz
    when /5/ then :buzz
    else n
  end

... но и това е 6 реда. Едва след това прочетох повече за case в ruby и ей сега качвам адекватно решение.

Кирил обнови решението на 14.10.2012 22:32 (преди над 11 години)

class Integer
def prime_divisors
(2..self.abs).select { |n| self % n == 0 and ('1' * n) !~ /^1?$|^(11+?)\1+$/ }
end
end
class Range
def fizzbuzz
- self.collect do |n|
- n = :fizz if n % 3 == 0
- n = :buzz if n.kind_of? Numeric and n % 5 == 0
- n = :fizzbuzz if n.kind_of? Numeric and n % 5 == 0 and n % 3 == 0
- n
+ self.map do |n|
+ case
+ when n % 15 == 0 then :fizzbuzz
+ when n % 3 == 0 then :fizz
+ when n % 5 == 0 then :buzz
+ else n
+ end
end
end
end
class Hash
def group_values
self.inject(Hash.new([])) { |result, item| result[item[1]] += [item[0]]; result }
end
end
class Array
def densities
- self.collect { |n| self.count n }
+ self.map { |n| self.count n }
end
end

Кирил обнови решението на 15.10.2012 01:32 (преди над 11 години)

class Integer
def prime_divisors
- (2..self.abs).select { |n| self % n == 0 and ('1' * n) !~ /^1?$|^(11+?)\1+$/ }
+ (2..abs).select { |n| self % n == 0 and ('1' * n) !~ /^1?$|^(11+?)\1+$/ }
end
end
class Range
def fizzbuzz
- self.map do |n|
- case
- when n % 15 == 0 then :fizzbuzz
- when n % 3 == 0 then :fizz
- when n % 5 == 0 then :buzz
- else n
+ map do |n|
+ if n % 15 == 0
+ :fizzbuzz
+ elsif n % 3 == 0
+ :fizz
+ elsif n % 5 == 0
+ :buzz
+ else
+ n
end
end
end
end
class Hash
def group_values
- self.inject(Hash.new([])) { |result, item| result[item[1]] += [item[0]]; result }
+ result = Hash.new{|hash, key| hash[key] = Array.new;}
+ each do |key, value|
+ result[value] << key
+ end
+ result
end
end
class Array
def densities
- self.map { |n| self.count n }
+ map { |n| count n }
end
end
  • Хм...с 8 реда метод ме пусна да предам домашното. Предпочетох да го оставя така, вместо:

    if n % 15 == 0 then :fizzbuzz
    elsif n % 3 == 0 then :fizz
    elsif n % 5 == 0 then :buzz
    else n
    end
    

Греша ли, че това е с едноредовите elsif-ове са кофти идея?

  • Ок, не знаех. Така и така го почнах от начало, реших да поразровя за дифолтните стойности в Hash. Попаднах на това обяснение от Gary Wright:

1) Hash.new(x) returns x when a key isn't found. It will be the same x for every key and won't store x in the hash, just return it on a key miss.

2) Hash.new { #code } will run the block on every key miss and return the resulting value but will not store the value in the hash.

3) Hash.new { |h,k| h[k] = #code } will evaluate the code, store it in the hash, and return the value on a key miss. Because the value is stored in the hash on the first key miss, the code will not execute on a subsequent lookup on the same key.

Очевидно мен ме устройва 3). Прав ли съм или като цяло тая идея Hash, с дифолтна стойност Array не е особено приятна?

  • Доста mind-blowing ми идва липсата на self., но явно тук така се прави - махнах ги.

Кирил обнови решението на 15.10.2012 01:45 (преди над 11 години)

class Integer
def prime_divisors
(2..abs).select { |n| self % n == 0 and ('1' * n) !~ /^1?$|^(11+?)\1+$/ }
end
end
class Range
def fizzbuzz
map do |n|
if n % 15 == 0
:fizzbuzz
elsif n % 3 == 0
:fizz
elsif n % 5 == 0
:buzz
else
n
end
end
end
end
class Hash
def group_values
- result = Hash.new{|hash, key| hash[key] = Array.new;}
+ result = Hash.new{ |hash, key| hash[key] = Array.new }
each do |key, value|
result[value] << key
end
result
end
end
class Array
def densities
map { |n| count n }
end
end

Разбирам за self., но ти просто имаш навици от Python... :) Тук self винаги е имплицитният получател при извикване на метод без явен такъв. Затова в 90% от случаите се изпуска.

За хеша — това с дифолтната стойнсот се ползва от време на време, но в случая ти връщаш този обект на потребителя и той се държи странно; не е като нормален хеш, в който като достъпиш липсващ ключ, ти връща nil. Вместо това ти връща някакъв празен списък, което, според мен, не трябва да е така. Ако позлваше хеша само вътрешно, щеше да е окей. Тук или трябва да намериш начин да махнеш тази дифолтна стойност някак (http://www.ruby-doc.org/core-1.9.3/Hash.html), или може да ползваш един от тези идиоми:

result = {}
# ...
result[value] ||= []
result[value] << key

Някои хора го записват на един ред, но аз лично не го харесвам така:

(result[value] ||= []) << key

Също да, тези едноредови if/then се избягват. На един ред е обикновено само в постфиксен вариант. В случая, може би Skeptic пречи.

Кирил обнови решението на 15.10.2012 12:20 (преди над 11 години)

class Integer
def prime_divisors
(2..abs).select { |n| self % n == 0 and ('1' * n) !~ /^1?$|^(11+?)\1+$/ }
end
end
class Range
def fizzbuzz
map do |n|
if n % 15 == 0
:fizzbuzz
elsif n % 3 == 0
:fizz
elsif n % 5 == 0
:buzz
else
n
end
end
end
end
class Hash
def group_values
- result = Hash.new{ |hash, key| hash[key] = Array.new }
+ result = {}
each do |key, value|
+ result[value] ||= []
result[value] << key
end
result
end
end
class Array
def densities
map { |n| count n }
end
end

Аз съм фен на едноредовите, ако ги идентираш така:

if    n % 15 == 0 then :fizzbuzz
elsif n % 3 == 0  then :fizz
elsif n % 5 == 0  then :buzz
else                   n
end

Love it or hate it, за мен това е добър начин за подреждане на просто "таблично" условие (без side effect-и и други сложнотии).