LINUX.ORG.RU

Поругайте код


0

1
  def words_pos(domain, word, start, stop)
    list = Position.where("`domain_id` = ? AND `word_id` = ? AND `time` BETWEEN ? AND ?", domain, word, start, stop)
    
    positions, i = [], 0

    while start < stop do
      
      if start.to_s(:db) == list[i].time.beginning_of_day.to_s(:db)
        positions << list[i].position.to_s
        i += 1
      else
        positions << '-'
      end

      start += 1.days
    end

    return positions
  end

Особенно 8-ю строку. Я не осилил Time...

☆
Ответ на: комментарий от daris

Это же не пхп, ты что, в Руби иногда и больше двух отступов бывает.

«Многоэтажность» в коде на императивном языке - фу.

r_asian ★☆☆
()

Цель у кода какая? Цикл бредовый какой-то. В запросе явно order не хватает, может в default_scope где, код 100% рассчитан на «order by time asc», да еще и на то что будет максимум одна запись в сутки. Я могу предположить что ты хочешь получить «историю» позиций типа «10 - 15 - 20 - 25» и т.д., в этом случае ты чего-то не то замутил.

«start.to_s(:db) == list[i].time.beginning_of_day.to_s(:db)» - что-то жуткое, «start.to_date == list[i].time.to_date» если хочешь проверить что тот же день.

Если я правильно понимаю че ты хотел - то примерно так это могло бы выглядеть.

def words_pos(domain, word, start, stop)
  positions = Position.where(:domain_id => domain, :word_id => word, :time => start..stop)
                      .group("date(`time`)").order("`time`")
  positions.map(&:position).map(&:to_s).zip(["-"] * (positions.length - 1)).flatten.compact  
end

anonymous
()

И да, в коде как таковом у тебя совсем хреново только сравнение дат через строки, идеологически можно придраться еще к ненужному return и формированию условия запроса. Тут алгоритм кривой в нет.

anonymous
()
Ответ на: комментарий от anonymous

Гм.. твой код делает нечто совершенно неприменимое. Однако, map на map я никогда не видел и это интересно. Покопаюсь :)

return не нужен как лишние 7 символов, разве что :) С ним читаемость выше, имо.

Про сравнение дней понял, спасибо.

daris ☆
() автор топика
Ответ на: комментарий от daris

Если бы ты хоть написал что ты хотел получить тем кодом. С моей точки зрения - он как раз делает что-то непонятное совершенно.

Мой код тянет с бд максимум одну запись ( group by time ) на каждый день, в порядке возрастания даты ( order by time asc ). Далее у каждой записи берем свойство .position ( первый map ), получаем список position'ов, конвертим в строки .to_s ( второй map).

Единственная магия - .zip, но на самом деле там тоже просто. Допустим у нас было ['1', '2', '3'] в positions после двух .map, .length этого дела - 3, ["-«] * (3-1) => [»-", "-«]. После zip'а будет [[„1“, »-«], [„2“, »-«], [„3“, nil]], nil в конце потому что у нас второй список недостаточно длинный, руби добивает nil'ами в этом случае. .flatten ожидаемо раскладывает это в [„1“, »-", «2», "-", «3», nil]. .compact убирает из массива nil'ы, получаем в итоге [«1», "-", «2», "-", «3»].

Как я понимаю это не то что тебе надо было на самом деле. В твоем коде "-" добавляется в случае если для данной даты нет записи в таблице, если я правильно понял в этом вся соль.

В таком случае можно что-то вроде

def words_pos(domain, word, start, stop)
  positions = Hash[
    Position.select("`time`, `position`")
            .where(:domain_id => domain, :word_id => word, :time => start..stop)
            .group("date(`time`)").order("`time`")
            .map{|p| [p.time.to_date, p.position]}          
  ]
  (start.to_date..stop.to_date).map{|day| positions[day] || "-" }
end
anonymous
()

>Поругайте
>positions, i = [], 0
Ну вот, собственно… тебе что, переводов строки жалко? Воспользуйся точкой с запятой.

Deleted
()

И да, временный контейнер «positions» не нужен, равно как и «i». Если не трогать логику происходящего, то писать скорее надо так =>

def words_pos(domain, word, start, stop)
  list = Position.where("`domain_id` = ? AND `word_id` = ? AND `time` BETWEEN ? AND ?", domain, word, start, stop)

  (start.to_date...stop.to_date).map do |day|
    if day == list.first.time.to_date
      list.shift.position.to_s
    else
      '-'
    end
  end
end

while с добавлением результатов в контейнер заменить на более лаконичный обход по Range между датами. Ссылка на «текущий» элемент массива «i» не нужна, т.к. ты по факту каждый раз переходишь к следующему элементу массива, старый потом не используются. С тем же успехом можно просто отрезать первый элемент массива когда надо.

anonymous
()

Не забываем, что в руби любое выражение, в том числе if имеет implicit возврат, как правило return - признак или хитровыебанного алгоритма или нарушение принципа про монастырь и чужой устав.

anonymous
()
Ответ на: комментарий от anonymous

Понял. Мне вполне ясно как этот код работает, но привычки укорачивать ещё нет. Где можно почитать про хороший стиль?

daris ☆
() автор топика

Очень плохо, что используется язык, где блоки кода выделяются табуляцией. Если мы и дальше будем выбирать такие языки, эта порочная особенность никогда не исчезнет, что, безусловно, недопустимо.

heisenberg ★★
()

list = Position.where(«`domain_id` = ? AND `word_id` = ? AND `time` BETWEEN ? AND ?», domain, word, start, stop)

SQL-инъекцию этому пациенту.

anonymous
()
Ответ на: комментарий от heisenberg

на руби блоки кода отделяются табуляцией? это что-то новенькое

redixin ★★★★
()
Вы не можете добавлять комментарии в эту тему: топик перемещен в архив.