Main

Ruby Archives

27.03.08

Euruko this weekend! [UPDATE]

This weekend the Euruko conference takes place in Prague. It's all about Ruby and I'll gonna be there.
I'm quite excited, as this is my first (big) conference I'm going to attend. I think most of the talks will be pretty advanced for a Ruby beginner like me, but I think I won't get dumber... ;-)

Unfortunately we'll probably miss Matz' Keynote, because our flight arrives at 09:30 in the morning and to think we'll be in the center of Prague at 10 o'clock would be really optimistic...

[UPDATE] We managed to get to prague university almost in time, so we saw most of the keynote:

Venue

I'm also looking forward to visiting Prague again, 'cause it really is a beautiful city - and affordable, too. That's why I'll stay until late tuesday. :-)

25.08.07

Flog Score

"Flog shows you the most torturous code you wrote. The more painful the code, the higher the score."

Damit ist eigentlich alles gesagt! Hier der Link: http://ruby.sadi.st/Flog.html

Die Score des Codes aus dem Posting zuvor:

ss1.rb:20: warning: `&' interpreted as argument prefix
Total score = 38.8476045651339

main#none: (11.9)
     2.7: assignment
     1.9: to_a
     1.7: flatten
     1.6: name
     1.5: map
     1.5: branch
     1.3: []
     1.3: find
     1.1: pp
     1.1: new
SecretSanta#initialize: (6.7)
     3.9: assignment
     2.8: dup
     1.3: shuffle!
     1.3: assign!
SecretSanta#no_two_indices_are_alike: (5.2)
     4.2: assignment
     1.4: ==
     1.3: branch
     1.3: all?

Und die von meinem Code:

Total score = 64.3800571683191

main#assign_santas: (27.4)
     7.0: assignment
     6.8: branch
     5.3: personal_santa
     4.7: can_be_santa_of?
     3.8: length
     3.4: rand
     2.4: each
     1.7: []
     1.5: swap_santas
     1.5: select
     1.3: delete_at
main#none: (23.6)
    10.0: assignment
     7.7: new
     3.2: personal_santa
     2.8: firstname
     2.8: lastname
     1.4: email
     1.2: puts
     1.1: each
     1.1: assign_santas
     1.1: branch
"Total score = 64.3800571683191"

Es war mir eine Ehre euch gequält zu haben...

21.08.07

Noch viel zu lernen?!?

Da bin ich grade über folgenden Ruby-Code zum Thema "Secret Santas" gestoßen und war recht beeindruckt, wie kurz dieser ist:

class Array
  def shuffle!
    replace sort_by { rand }
  end
end

class SecretSanta
  include Enumerable

  def initialize(people)
    @from, @to = people.dup.shuffle!, people.dup
    assign!
  end

  def assign!
    @to.shuffle! until no_two_indices_are_alike
  end

  def each(&block)
    @from.zip(@to).each &block
  end

private
  def no_two_indices_are_alike
    all? { |a, b| a != b }
  end
end

s = SecretSanta.new(Person.find(:all))
# Print Secret Santa pairings
pp Hash[*s.to_a.flatten.map {|person| person.name}]

Nur verstehen tue ich bis jetzt wenig. Mal sehen, ob sich das in nächste Zeit ändert, aber abgesehen davon, bin ich kein Fan von solchem sehr kompakten Code. Ich weiss ja nicht ob Ruby-Spezialisten sowas auf anhieb lesen können (auch, wenn sie nicht wissen, welches Problem gelöst werden soll), aber ich könnte es nicht. IMHO ist lesbarer Code wesentlich besser, vor allem, was die Wartbarkeit angeht. Und wenn man dafür die doppelte Anzahl Codezeilen benötigt...

Oder ist ultrakompakter Quellcode erstrebenswert?

14.08.07

Learning Ruby: The secret santas [Update]

Da ich grade dabei bin Ruby zu lernen, möchte ich mal ein kleines Programm zeigen und Probleme auflisten, die ich damit hatte.

Auf rubyquiz.com gibt es sehr viele Aufgaben, die man mit Ruby lösen kann und soll. Ich kann diese Seite nur empfehlen. Von dieser stammt auch das folgende Problem: Secret Santas.

Zu deutsch würde man das wohl als "Wichteln" bezeichnen. So werden gegenseitig zufällig Wichtelpartner zugeordnet. Die Einschränkung ist, dass Personen aus der selben Familie nicht gegenseitig zugeteilt werden dürfen.

Nachdem ich das Grundgerüst relativ schnell stehen hatte und zumindest teilweise das Problem mit den gleichen Nachnamen gelöst hatte, bestand am Ende das Problem, dass manchmal noch eine Person zugeteilt werden musste, diese aber den gleichen Nachnamen hatte, wie die Person, der noch der Wichtelpartner fehlte.

So habe ich mich auf die Suche nach einer Lösung gemacht, und meinte das Problem mathematisch lösen zu können/müssen (Stichwort: Permutationen).

Nachdem ich absolut nicht auf den grünen Zweig gekommen bin, habe ich dann doch mal in die Lösung geguckt. Eine elegante Lösung ist der Hill Climbing Algorithmus. Hier werden die Wichtelpartner zunächst einfach zufällig zugewiesen und am Ende wird die Liste der Personen mit ihren Partnern durchgegangen und ggf. falsche Übereinstimmungen (gleicher Nachname) durch vertauschen der jeweiligen Partner gelöst.

Also war's doch etwas unkomplizierter, als ich es mir vorher vorgestellt hatte. Meine Lösung:

[Update:] Bei der Suche nach geeigneten Kandidaten für einen Tausch der Partner, muss auf jeden Fall noch folgender Ausdruck nach dem && hinzugefügt werden:

people.select { |p| p.personal_santa.can_be_santa_of?(person)
&& person.personal_santa.can_be_santa_of?(p) }

Ansonsten kann es trotzdem vorkommen, dass falsche Wichtelpartner zugeordnet werden.

class Person
  attr_writer :personal_santa
  attr_reader :firstname, :lastname, :email, :personal_santa

  def initialize (firstname, lastname, email)
    @firstname = firstname
    @lastname = lastname
    @email = email
  end

  def can_be_santa_of?(other)
    @lastname != other.lastname
  end
end

#switches the two personal_santas of the passed people
def swap_santas (person1, person2)
  temp = person1.personal_santa
  person1.personal_santa = person2.personal_santa
  person2.personal_santa = temp  
end

#assigns each person his secret santa
def assign_santas(people, santas)
  people.each { |person| person.personal_santa = santas.delete_at
(rand(santas.length)) } #assigns santas randomly
  people.each { |person| 
    unless person.personal_santa.can_be_santa_of? person
      #finds possible candidates for a swap
      candidates = people.select { |p|
p.personal_santa.can_be_santa_of?(person)
&& person.personal_santa.can_be_santa_of?(p) }
      swap_santas(person, candidates[rand(candidates.length)])
    end
    }
end

person1 = Person.new("Daniel","Pietzsch","[email protected]")
person2 = Person.new("...") #parameter in the above format
person3 = Person.new("...")
person4 = Person.new("...")
person5 = Person.new("...")
person6 = Person.new("...")

people = [person1, person2, person3, person4, person5, person6]
santas = Array.new(people) #Copy of the people array

assign_santas(people, santas) #assigns each person his secret santa

#output
people.each {|person| puts "#{person.firstname} #{person.lastname}:
<#{person.email}>\nPersonal Santa: #{person.personal_santa.firstname}
#{person.personal_santa.lastname}\n\n"}

About

DanielHi. I'm Daniel Pietzsch and this is my innoQ-Blog. I'm a 26y old student at FH Bochum and working student at innoQ.
In this blog I mainly write about the progress concerning my diploma thesis which will be an in-house application for innoQ based on Ruby on Rails, but some other (geek) stuff might appear here, too.

daniel [dot] pietzsch [alt-L] innoq [dot] com

I recommend

Categories

Recent Comments

License

Creative Commons License This weblog is licensed under a Creative Commons License.
Powered by
Movable Type 3.31