2016-04-05 3 views
-3

Ich habe eine Zufallszahl und ich möchte es in mehrere Teile (Summanden) mit Bedingungen teilen, dass ein Teil nicht mehr als 20 sein kann und die Teile so nah sein müssen so gut wie möglich.Split-Nummer in gleiche Teile oder was am nächsten ist

Wenn zum Beispiel meine Zufallszahl 41 ist, sollte Addenden 14 sein, 14, 13. Wenn Zufallszahl 60 Addenden 20 sein sollte, 20, 20. Wenn Zufallszahl 21 Addenden 11 sein sollte, und 10 und so weiter.

Mein Code ist in Ruby (Rails), daher würde ich eine Antwort sehr schätzen, die eine effiziente Implementierung von diesem in Ruby bietet, obwohl auch Pseudocode oder andere Programmiersprachen willkommen sind.

Dies ist, was ich für Arrays gefunden, aber ich brauche wirklich diese Sache mit Zahlen zu tun: „Splitting an array into equal parts in ruby

+1

Willkommen bei SO. Bitte lesen Sie "[fragen]" einschließlich der Links auf dieser Seite. Sie bitten uns, Code für Sie zu schreiben? Dafür ist Stack Overflow nicht geeignet. Stattdessen, Sie tun die Forschung, Sie versuchen, dann, wenn Sie auf ein Problem stoßen, zeigen Sie uns, was Sie versuchten, und wir helfen Ihnen, es zu beheben. http://meta.stackoverflow.com/q/261592/128421 ist nützlich zu lesen. –

+0

Wie viele Summanden erwarten Sie? – Aetherus

+0

@Aetherus Es ist egal, ich habe eine maximale Grenze für meine Zufallszahl, damit es nicht zu wild wird. – mizurnix

Antwort

9

Sie diesen kühlen Einzeiler verwenden können. Es sollte von jeder Menge Stücktrenn arbeiten Sie wollen:

def split_into n, p 
    [n/p + 1] * (n%p) + [n/p] * (p - n%p) 
end 

print (split_into 32, 3) # => [11, 11, 10] 

Er teilt im wesentlichen die Zahl in gleiche Teile aufteilt, und der Rest wird durch den ersten, die (1 für jeden). Das und die Tatsache, dass Sie Arrays zusammen multiplizieren und addieren können, etwa so:

[1] * 3  # => [1, 1, 1] 
[1] + [2] # => [1, 2] 

EDIT: In Anbetracht der Regel, dass jedes Stück kleiner als 20 sein sollte, können Sie die ideale Menge von Stücken wie vorgeschlagen berechnen kann @Cary Swoveland:

p = (n/20.0).ceil 
+1

Sauberste Sache, die ich seit Ewigkeiten gesehen habe! Und coole Mathe, das ist genau das, was ich zu haben hoffte, würde existieren, aber es war in meinen Unterlagen nicht annähernd. Ich werde immer noch einen Weg finden müssen, wie man den dynamischen Wert von 'p' berechnet, aber das wird Spaß machen. Und ich habe nicht klar erklärt warum und wie es in meiner Frage dynamisch ist, also akzeptiere ich das. Danke – mizurnix

+0

@CarySwoveland Du hast die Frage richtig beantwortet. Obwohl ich glaube, dass diese Antwort ziemlich nah ist. Es brauchte nur eine kleine Hinzufügung, nämlich "p" innerhalb der Methode verschieben und auf 1 setzen. Dann in eine Schleife einfügen und "p + = 1" bis "n/p <21" – mizurnix

+0

@CarySwoveland Dies ist die Antwort, über die wir sprechen ungefähr richtig? Mit meiner Schleife 'split_into 1_000_000, 1) # => [1000000]' ist nicht wahr. Seit 1000000/1> 20 versucht es dann 1000000/2, dann 1000000/3 und so weiter, bis es den Wert erreicht, der eine Zahl zurückgibt, die entweder 20 oder weniger ist. Danach funktioniert Slys Code wie ein Charm – mizurnix

3

Es gibt nicht eine integrierte Funktion ist, dies zu tun.

Ich kann die Lösung für Sie schreiben, aber im Allgemeinen sollten Sie Ihren eigenen Versuch in StackOverflow Fragen enthalten. Diese Art von Problem scheint praktisch zu sein, um die Grundlagen der Rubinsprache zu erlernen. Ich empfehle ein Ruby-Lehrbuch, wenn Sie nicht sicher sind, wo Sie anfangen sollen.

def split_number_into_three(number) # i.e. number=32 
    base = Array.new(3, (number/3)) # i.e. base=[10,10,10] 
    remainder = number % 3   # i.e. remainer=2 
    return base if remainder.zero? 
    while remainder > 0 
    base.each_with_index do |num, idx| 
     if remainder > 0 
     base[idx] += 1 
     remainder -= 1 
     end 
    end 
    end 
    base 
end 

Ausführen dieses Code:

irb(main):035:0> split_number_into_three(32) 
=> [11, 11, 10] 
+0

groß, super Max – illusionist

+1

Vielen Dank. Ich habe diese Methode implementiert und es funktioniert großartig. Und natürlich ist es sehr einfach, es so zu ändern, dass es "split_number_into_n" genannt wird, um die Anzahl der Teile zu bestimmen, in die ich meine Nummer teilen möchte. Die Antwort von SlySherZ scheint immer näher an dem zu liegen, was ich gefragt habe, also stimme ich dem zu und akzeptiere, dass – mizurnix

+0

mizurnix offensichtlich nicht wahr sein kann, weil diese Methode den größten zulässigen Wert (d. H. 20) nicht berücksichtigt.Hinweis: 'split_into 1_000_000, 1) # => [1000000]'. –

4

-Code

n die gegebene Zahl Let sein, die geteilt werden soll, und m der maximale Wert jeder Komponente.

def doit(n,m) 
    nbr_components = (n/(m.to_f)).ceil 
    smaller, nbr_larger = n.divmod(nbr_components) 
    { smaller=>nbr_components-nbr_larger, smaller+1=>nbr_larger }. 
    delete_if { |_,v| v.zero? } 
end 

Fixnum#divmod ist eine oft übersehene Methode mit vielen Einsatzmöglichkeiten.

Beispiele

(1..300).to_a.sample(15).sort.each { |n| puts "doit(#{n},20) = #{doit(n,20)}" } 
doit(2,20) = {2=>1} 
doit(7,20) = {7=>1} 
doit(13,20) = {13=>1} 
doit(19,20) = {19=>1} 
doit(32,20) = {16=>2} 
doit(36,20) = {18=>2} 
doit(47,20) = {15=>1, 16=>2} 
doit(61,20) = {15=>3, 16=>1} 
doit(77,20) = {19=>3, 20=>1} 
doit(146,20) = {18=>6, 19=>2} 
doit(149,20) = {18=>3, 19=>5} 
doit(160,20) = {20=>8} 
doit(199,20) = {19=>1, 20=>9} 
doit(253,20) = {19=>7, 20=>6} 
doit(275,20) = {19=>5, 20=>9} 

doit(11_347_155, 20) 
    #=> {19=>5, 20=>567353} 
5*19 + 567353*20 
    #=> 11347155 

Erläuterung

Angenommen:

n = 77 
m = 20 

Die Schritte sind wie folgt:

nbr_components = (n/(m.to_f)).ceil 
    #=> (77/20.0).ceil 
    #=> 3.85.ceil 
    #=> 4 
smaller, nbr_larger = n.divmod(nbr_components) 
    #=> 77.divmod(4) 
    #=> [19, 1] 
smaller 
    #=> 19 
nbr_larger 
    #=> 1 
h = { smaller=>nbr_components-nbr_larger, smaller+1=>nbr_larger } 
    #=> {19=>3, 20=>1} 
h.delete_if { |_,v| v.zero? } 
    #=> {19=>3, 20=>1} 
Verwandte Themen