2012-12-06 5 views
6

Bedingungen zu 100 aufaddierenWas ist die Ruby-artig jede einzigartige Kombination von drei positiven ganzen Zahlen zu erzeugen, die

a + b + c = 100 
a,b,c positive integers or 0 

gewünschter Ausgabe:

[ 
    [0,0,100], 
    [0,1,99 ], 
    ... # all other permutations 
    [99,1,0 ], 
    [100,0,0] 
] 

Stackoverflow sagt mein Beitrag nicht hat viel Kontext, um die Code-Abschnitte zu erklären. Sind Sie einverstanden? (Dies ist Fülltext auf ihre Forderungen zu erfüllen)

+0

erinnern einige der Antworten wählen – tokland

Antwort

13

ich schreiben würde:

(0..100).flat_map { |x| (0..100-x).map { |y| [x, y, 100-x-y] } } 
#=> [[0, 0, 100], [0, 1, 99]], ..., [99, 1, 0], [100, 0, 0]] 

Website Anmerkung 1: Dies ist ein klassisches Beispiel, in dem list-Comprehensions Glanz (und noch mehr, wenn es ein Zustand irgendwo war). Da Ruby keine LC hat, müssen wir die typische Umwandlung zu OOP durchführen: N-1flat_map 's + map. Es wäre großartig, LCs in Ruby zu haben (siehe this feature request), Scala hat bewiesen, dass sogar eine reine OOP-Sprache von diesem syntaktischen Zucker profitiert (obwohl ich die Prävention von den Entwicklern aufgrund des impliziten iterierbaren Protokolls/Methode verstehen kann). Auf einer imaginären Rubin, die sie unterstützt Sie schreiben würde:

[[x, y, 100-x-y] for x in 0..100 for y in 0..100-x] # imaginary Ruby 

Exkurs 2: Stellen Sie sich vor, dass Sie einen weniger speicherintensive Lösung bevorzugen (Sie wahrscheinlich das gesamte Array nicht brauchen). Ein fauler Lösung mit Ruby-2.0 erfordert nur ein paar [lazy][2] Proxies hinzuzufügen:

(0..100).lazy.flat_map { |x| (0..100-x).lazy.map { |y| [x, y, 100-x-y] } } 

Side Anmerkung 3: Nur der Vollständigkeit halber, in der Linie der @akuhn Antwort, eine weitere faule Lösung unter Verwendung von Aufzählungen:

Enumerator.new do |e| 
    (0..100).each { |x| (0..100-x).each { |y| e.yield([x, y, 100-x-y]) } } 
end 
+0

Nicht ein schlechter Ansatz, aber ich würde nur alle möglichen Kombinationen von a, b, und c erzeugen und eine 'find_all' von Kombinationen tun, die zu 100 –

+2

@AndrewGrimm aufaddieren Ihre Ansatz wird etwa 500.000 Mal so viel Arbeit wie Tokland tun. – dbenhur

+0

@dbenhur ja, aber das ist Arbeit Ruby würde tun, nicht arbeiten würde ich tun! –

4

Hier ist meine Lösung

for a in 0..100; for b in 0..100-a; p [a,b,100-a-b]; end; end 

, die ich liest sich fast wie @ Verständnis tokland Liste finden. Wenn Sie möchten, um die Werte verwenden, weiter stromabwärts, anstatt sie zu drucken, setzen Sie den Code in einem Generator Methode

def generate 
    return enum_for(:generate) unless block_given? 
    for a in 0..100 
    for b in 0..100-a 
     yield [a,b,100-a-b] 
    end 
    end 
end 

, die dann wie in

generate { |a,b,c| puts [a,b,c] } 

oder wie in

verwendet wird
generate { |each| p each } 

oder wie in

p generate.to_a 

, die alle erzeugten Tupel drucken.

+0

Manchmal benutze ich auch diesen Python-Generator-ähnlichen Ansatz, obwohl es sich weniger funktional anfühlt (FP sense). Wie auch immer, anstatt einen 'to_enum'-Wächter einzufügen (welchen Kern Ruby-Methoden vielseitiger machen), können Sie auch entscheiden, immer einen Enumerator zurückzugeben, der für potentiell große Ausgaben sinnvoll ist: 'Enumerator.new {| yielder | ... yielder.field x} '. – tokland

+0

@tokland Was ist der Unterschied zwischen 'to_enum' und einem Enumerator? Nur eine Frage des Stils, oder gibt es einen Unterschied in der Umsetzung? Ich würde mir vorstellen, dass beide Fasern für Korotinen verwenden. – akuhn

+0

@tokland die Frage war über "Ruby-style" nicht eine streng "funktionale Programmierung" :) – akuhn

3

ich die Rubin-ish Art und Weise sagen würde (was die effizienteste Art und Weise nicht mit irgendwelchen Mitteln ist), ist dies:

(0..100).to_a.repeated_permutation(3).find_all{|triplet|triplet.inject(:+)==100} 

Der einzige nicht-transparente Teil dieser Kette ist die to_a, die konvertiert das durch (0..100) angegebene Bereichsobjekt in ein Array (Bereiche sind faul, was nicht mit repeated_permutation funktioniert).

+0

Ich mag es! Obwohl es am meisten Ruby-ish (d. H. Magisch, knappe und natürliche Sprache-isch) scheint, werde ich @ tokland's Antwort in diesem Fall akzeptieren. Ich bin jedoch offen für Diskussionen. –

+0

Kein Zweifel, das ist einfacher zu verstehen (ich würde nicht mehr sagen Ruby-sh, warum ist das?), Und wenn ich wüsste, dass N immer klein sind, würde ich wahrscheinlich dafür gehen. Vom rechnerischen Standpunkt aus ist die Umwandlung eines O (n^2) -Problems in ein O (n^3) jedoch etwas zweifelhaft, um es gelinde auszudrücken. Erhöhen Sie N ein wenig und Sie werden in große Schwierigkeiten geraten. – tokland

+1

Das ist nett, aber es findet nicht alle Kombinationen. Es enthält zum Beispiel "[0,0,100]", aber nicht "[100,0,0]". – Adam

Verwandte Themen