Ruby и красивый код #2

ноября 18, 2010  |  Published in Ruby, Основы  |  15 Comments

rubyЭто 2я статья из серии «Ruby и красивый код».
Ruby и красивый код #1

Задача №1 по высокоуровневому программированию (ФГОУ ДПО МЭТТ ГАИ)
Эта задача использовались автоматизированной системой тестирования при проведении контрольных работ по предметам: «Программирование на языке высокого уровня» и «Программное обеспечение компьютерных сетей» в 2006-2007 учебном году.

Задача: Дан целочисленный массив. Необходимо вывести вначале его элементы с четными индексами, а затем — с нечетными.

Решение #1

        arr = (1..9).to_a
        indexes, p, np  = [], [], [] 
        arr.each_index{|i| indexes << i}
        for i in indexes 
          if i % 2 == 0
            p << i
          else 
            np << i
          end
        end

        for i in p
          puts arr[i]
        end
        
        puts "---"
        
        for i in np
          puts arr[i]
        end
        
        

Решение #2

        arr = (1..9).to_a

        arr.each_with_index do |elem, index|
          puts elem if (index % 2) == 0
        end

        arr.each_with_index do |elem, index|
          puts elem if (index % 2) != 0
        end
   

Решение #3 - Немного измененное решение #2

arr = (1..9).to_a
n, np = [], []

arr.each_with_index do |elem, index|
  if (index % 2) == 0
    p << elem
  else
    np << elem
  end
end
        
puts p
  puts "---"
puts np

Первое решение задачи - решение человека, не знающего о существовании метода each_with_index (мое). Второе решение - решение моего друга, который значительно более опытный програмист чем я и который знает о существовании метода each_with_index (Максим, спасибо!). Третье решение - мое, его я создал для решения некоторых недостатков решения номер 2, а именно: вместо двух обходов по массиву теперь остался лишь один, кроме того значения под парными и непарными индексами не просто выводятся на экран, но и сохраняются в соответствующие масивы p и np для возможности их дальнейшего использования.

Выводы: Первое решение можно отнести к over engineering, так как в нем слишком много кода, что связано с малым опытом работы на языке Ruby. Второй метод наиболее лаконичный и читабельный, а третий найдет большее применение.

Создаем себе Золотое правило: Прежде, чем писать код, следует убедиться в том, что метода реализующего полностью или частично необходимую функциональность, нету. Спешка и нежелание работать с документацией - большие враги программиста!

Обновление #1:
Вот придумал еще один интересный способ решения:

arr = (1..9).to_a
p, np  = [], [] 

arr.each_index do |i| 
  i%2 == 0 ? p << i : np << i
end

puts arr.values_at(*p)
puts arr.values_at(*np)

Обновление #2:
Максим предоставил еще более изящный вариант решения задачи:

arr = (1..9).to_a

even_indexes, odd_indexes = (0..(arr.size - 1)).partition  {|i| i % 2 == 0}

puts arr.values_at(*even_indexes)
puts arr.values_at(*odd_indexes)

Браво!

Tags: , ,

Responses

  1. admin says:

    ноября 18, 2010 at 20:56 (#)

    Предлагайте свои варианты решения сей задачи.

  2. RomanY says:

    ноября 18, 2010 at 20:58 (#)

    а как же логические методы .even? и .odd? ?

  3. RomanY says:

    ноября 18, 2010 at 21:23 (#)

    Как вариант с занесением в разные массивы:

    array = (10..19).to_a
    p,np = (0...array.size).to_a.partition{|i| i.even? }.each{ |a| a.map!{ |i| array[i]}}
    p p
    p np
    
  4. RomanY says:

    ноября 18, 2010 at 21:31 (#)

    ну или вот так:

    array, p, np = (10..19).to_a, [], []
    array.each_with_index{ |e, i| i.even? ? p << e : np << e }
    p p
    p np
    
  5. admin says:

    ноября 18, 2010 at 21:47 (#)

    RomanY, здорово! ;-)

  6. dre3k says:

    ноября 19, 2010 at 21:50 (#)

    RomanY и Максим уже показали много всего красивого, лаконичного, правильного…
    Так что следующие варианты приведены сугубо для рашрирения кругозора и знания ruby.

    # 1
    arr = (10..19).to_a
    switch = false
    new = arr.partition{|i| switch = !switch}
    p new.first
    p new.last
    
    # 2
    arr = (10..19).to_a
    new = [[], []]
    (0..arr.size).step(2){|i| arr[i] && (new.first < < arr[i])}
    (1..arr.size).step(2){|i| arr[i] && (new.last << arr[i])}
    p new.first
    p new.last
    
    # 3
    arr = (10..19).to_a
    new = [[], []]
    (0..arr.size).each{|i| ((i.even?)..(i.even?) ? new.first : new.last) << arr[i]}
    p new.first.compact
    p new.last.compact
    
    # 4
    arr = (10..19).to_a
    hash = arr.inject({:even => [], :odd => []}) do |hash, element|
      hash[:even].length < = hash[:odd].length ?
        hash[:even] << element : hash[:odd] << element
      hash
    end
    p hash[:even]
    p hash[:odd]
    
    # 5
    arr = (10..19).to_a
    new = arr.inject([]) do |result, element|
      (index = result.size).even? ?
        result.insert(index / 2, element) : result << element
      result
    end
    p new[0, (new.size.to_f / 2).round]
    p new[(new.size.to_f / 2).round, (new.size.to_f / 2).floor]
    

    Ссылки:


  7. admin says:

    ноября 19, 2010 at 22:42 (#)

    dre3k, спасибо за полезные, особенно в плане знакомства с новыми методами, примеры!

  8. val says:

    ноября 24, 2010 at 23:12 (#)

    Поскольку в условии задачи не сказано что элементы должны выводиться в том же порядке в каком встречаются в исходном массиве, то можно предложить еще такой вариант:

    arr, res = (10..19).to_a, []
    arr.each_with_index do |e, i| 
     i%2 == 0 ? res.insert(0, e) : res.push(e)
    end
    p res
    
  9. Ruby и красивый код #3 | Разработка на Ruby и Rails c нуля says:

    декабря 28, 2010 at 14:40 (#)

    [...] Предыдущие статьи из рубрики: Ruby и красивый код #1 Ruby и красивый код #2 [...]

  10. Dmitry says:

    августа 11, 2011 at 16:55 (#)

    #!/usr/bin/ruby -w
    #Дан целочисленный массив. Необходимо вывести вначале его элементы с четными
    #идексами, а затем — с нечетными.
    arr = Array.new(10) { |index| index+1 }
    arr.each_with_index { |elem, index| print «#{elem}» unless index%2 != 0 }
    puts «»
    arr.each_with_index { |elem, index| print «#{elem}» unless index%2 == 0}
    puts «»

  11. QtRoS says:

    февраля 13, 2012 at 22:35 (#)

    Блин, изучаю руби пару дней, но по-моему мое решение лучше большинства …

    arr = [1, 2, 3, 4, 5, 6, 7, 8]
    
    arr.each_index { |index| 
      if index.even?
        puts arr[index]
      end
    }
    
    arr.each_index { |index| 
      if index.odd?
        puts arr[index]
      end
    }
    
  12. bin0m says:

    мая 13, 2012 at 15:21 (#)

    a = [1, 2, 3, 4, 5, 6, 7, 8]

    a1 = []
    a2 = []

    a.length.times { |i| (i.odd? ? a1 : a2) << a[i] }

    puts a1
    puts a2

  13. Duke says:

    октября 15, 2012 at 14:11 (#)

    Понравилось решение Val’a, только всё-таки добавил бы исходный порядок следования элементов

    arr, res = (10..19).to_a, []
    arr.each_with_index do |e, i|
      i%2 == 0 ? res.insert(i/2, e) : res.push(e)
    end
    p res
    
  14. ChesterLife says:

    ноября 6, 2012 at 12:27 (#)

    p arr.partition { |e| arr.index(e).even? }

  15. vegoshin says:

    июня 1, 2013 at 17:05 (#)

    [language]
    [* 1..100].partition { |i| i.even? } .each { |e| p e }
    [language]

Leave a Response

Для подсветки кода используйте BB - коды: [language]...[/language], где language может быть: ruby, javascript, css, html.