Paradosso della ripartizione


10

Dato:

  • Un numero naturale S .
  • Un elenco di N pesi razionali W che si sommano a 1.

Restituisce un elenco L di N numeri interi non negativi, in modo che:

(1) sum(L) = S
(2) sum((S⋅W_i - L_i)^2) is minimal

In altre parole, approssimare S⋅W_is con numeri interi il più vicino possibile.

Esempi:

1 [0.4 0.3 0.3] = [1 0 0]
3 [0 1 0] = [0 3 0]
4 [0.3 0.4 0.3] = [1 2 1]
5 [0.3 0.4 0.3] = [2 2 1] or [1 2 2] but not [1 3 1]
21 [0.3 0.2 0.5] = [6 4 11]
5 [0.1 0.2 0.3 0.4] = [1 1 1 2] or [0 1 2 2]
4 [0.11 0.3 0.59] = [1 1 2]
10 [0.47 0.47 0.06] = [5 5 0]
10 [0.43 0.43 0.14] = [4 4 2]
11 [0.43 0.43 0.14] = [5 5 1]

Regole:

  • È possibile utilizzare qualsiasi formato di input o fornire semplicemente una funzione che accetta l'input come argomenti.

Sfondo:

Questo problema si presenta quando si visualizzano S dei diversi tipi di elementi in proporzioni diverse W i in relazione ai tipi.

Un altro esempio di questo problema è la rappresentanza politica proporzionale, si veda il paradosso della ripartizione . Gli ultimi due casi di test sono noti come paradosso dell'Alabama.

Come statistico, ho riconosciuto questo problema come equivalente a un problema riscontrato nell'identificare le dimensioni del campione durante la conduzione di un campione stratificato. In quella situazione, vogliamo rendere la proporzione di ogni strato nel campione uguale alla proporzione di ogni strato nella popolazione. - @tomi


Potresti dire a parole qual è il compito? Ho problemi a decomprimere le espressioni in qualcosa di intuitivo.
xnor

Entrambi dovrebbero essere ≤, fissi. Il compito è presentare un numero intero come somma di numeri interi basati sui pesi. Il resto dovrebbe essere distribuito favorendo i pesi più alti, anche se non sono sicuro che questo requisito sia codificato correttamente? Questo è interessante perché round(A + B) != round(A) + round(B), una breve soluzione richiede una visione di ciò che sta accadendo qui.
glebm,

1
Forse cambi le regole per minimizzare la somma delle distanze al L[i] - S*W[i]quadrato, invece della regola 2 e della regola 3. Questo sarebbe approssimativo S*W[i].
Jakube,

1
Inoltre [0 1 2 2] è un'altra possibile soluzione per5 [0.1 0.2 0.3 0.4]
Jakube,

1
Forse dovresti aggiungere un esempio per 1 [0.4 0.3 0.3]
aditsu smetti perché SE è MALE

Risposte:


6

APL, 21

{{⍵+1=⍋⍋⍵-⍺}⍣⍺/⍺0×⊂⍵}

Questa è una traduzione dalla risposta CJam a 37 byte di aditsu .

Provalo online .

Spiegazione

 {      ⍵-⍺}            ⍝ Right argument - left argument.
 {  1=⍋⍋⍵-⍺}            ⍝ Make one of the smallest number 1, others 0.
 {⍵+1=⍋⍋⍵-⍺}            ⍝ Add the result and the right argument together.
 {⍵+1=⍋⍋⍵-⍺}⍣⍺          ⍝ Repeat that S times. The result of each iteration is the new right argument.
                  ⊂⍵    ⍝ Return enclosed W, which is taken as one unit in APL.
               ⍺0×⊂⍵    ⍝ Return S*W and 0*W.
{{⍵+1=⍋⍋⍵-⍺}⍣⍺/⍺0×⊂⍵}   ⍝ Make S*W the left argument, 0*W the right argument in the first iteration.

7

Python 2, 95 83 132 125 143

Il mio primo (e secondo) (e terzo) algoritmo ha avuto problemi, quindi dopo una (un'altra!) Riscrittura e altri test, ecco (spero davvero) una soluzione corretta e veloce:

def a(b,h):
 g=h;c=[];d=[]
 for w in b:f=int(w*h);d+=[f];c+=[h*w-f];g-=f
 if g:
  for e in sorted(c)[-g:]:i=c.index(e);c[i]=2;d[i]+=1
 return d

La fonte prima del minificatore ora appare come:

# minified 143 bytes
def golfalloc(weights, num):
    # Tiny seq alloc for golfing
    gap = num;
    errors = [];
    counts = []
    for w in weights :
        count = int(w*num);
        counts += [count];
        errors += [num*w - count];
        gap -= count
    if gap:
        for e in sorted(errors)[-gap:] :
            i = errors.index(e);
            errors[i] = 2;
            counts[i] += 1
    return counts

I test ritornano:

Pass                    Shape    N               Result Error                        AbsErrSum
ok            [0.4, 0.3, 0.3]    1            [1, 0, 0] -0.60,+0.30,+0.30                 1.20
ok                  [0, 1, 0]    3            [0, 3, 0] +0.00,+0.00,+0.00                 0.00
ok            [0.3, 0.4, 0.3]    4            [1, 2, 1] +0.20,-0.40,+0.20                 0.80
ok            [0.3, 0.4, 0.3]    5            [2, 2, 1] -0.50,+0.00,+0.50                 1.00
ok            [0.3, 0.2, 0.5]   21           [6, 4, 11] +0.30,+0.20,-0.50                 1.00
ok       [0.1, 0.2, 0.3, 0.4]    5         [1, 1, 1, 2] -0.50,+0.00,+0.50,+0.00           1.00
ok          [0.11, 0.3, 0.59]    4            [1, 1, 2] -0.56,+0.20,+0.36                 1.12
ok         [0.47, 0.47, 0.06]   10            [5, 5, 0] -0.30,-0.30,+0.60                 1.20
ok         [0.43, 0.43, 0.14]   10            [4, 4, 2] +0.30,+0.30,-0.60                 1.20
ok         [0.43, 0.43, 0.14]   11            [5, 5, 1] -0.27,-0.27,+0.54                 1.08

Questo algoritmo è simile alle altre risposte qui. È O (1) per num, quindi ha lo stesso tempo di esecuzione per numeri interi 10 e 1000000. È teoricamente O (nlogn) per il numero di pesi (a causa del tipo). Se questo resiste a tutti gli altri casi di input complicati, sostituirà l'algoritmo di seguito nella mia casella degli strumenti di programmazione.

Per favore, non usare quell'algoritmo con qualcosa che non sia da golf. Ho fatto compromessi in termini di velocità per ridurre al minimo le dimensioni della fonte. Il codice seguente utilizza la stessa logica ma è molto più veloce e più utile:

def seqalloc(anyweights, num):
    # Distribute integer num depending on weights.
    # weights may be non-negative integers, longs, or floats.
    totalbias = float(sum(anyweights))
    weights = [bias/totalbias for bias in anyweights]
    counts = [int(w*num) for w in weights]
    gap = num - sum(counts)
    if gap:
        errors = [num*w - q for w,q in zip(weights, counts)]
        ordered = sorted(range(len(errors)), key=errors.__getitem__)
        for i in ordered[-gap:]:
            counts[i] += 1
    return counts

Il valore di num non influisce in modo significativo sulla velocità. L'ho provato con valori da 1 a 10 ^ 19. Il tempo di esecuzione varia linearmente con il numero di pesi. Sul mio computer ci vogliono 0,15 secondi con 10 ^ 5 pesi e 15 secondi con 10 ^ 7 pesi. Si noti che i pesi non sono limitati alle frazioni che si sommano a uno. Anche la tecnica di ordinamento usata qui è circa due volte più veloce dello sorted((v,i) for i,v in enumerate...)stile tradizionale .

Algoritmo originale

Questa era una funzione nella mia cassetta degli attrezzi, modificata un po 'per il golf. Era originariamente da una risposta SO . Ed è sbagliato

def seqalloc(seq, num):
    outseq = []
    totalw = float(sum(seq))
    for weight in seq:
        share = int(round(num * weight / totalw)) if weight else 0
        outseq.append(share)
        totalw -= weight
        num -= share
    return outseq

Fornisce un'approssimazione, ma non è sempre corretto, sebbene la somma (outseq) == num sia mantenuta. Veloce ma non raccomandato.

Grazie a @alephalpha e @ user23013 per aver individuato gli errori.

EDIT: impostare totalw (d) su 1 poiché OP specifica che la somma dei pesi sarà sempre 1. Ora 83 byte.

EDIT2: bug risolto per [0.4, 0.3, 0.3], 1.

EDIT3: algoritmo difettoso abbandonato. Aggiunto uno migliore.

EDIT4: Questo sta diventando ridicolo. Sostituito con l'algoritmo corretto (lo spero davvero).

EDIT5: aggiunto codice non golfy per gli altri che potrebbero voler utilizzare questo algoritmo.


4
a([0.4, 0.3, 0.3], 1)ritorna [0, 1, 0], mentre la risposta corretta è [1, 0, 0].
alephalpha,

1
Ancora sbagliato. a([0.11,0.3,0.59],4)restituito [0, 1, 3]. Dovrebbe essere [1, 1, 2].
jimmy23013,

1
f([0.47,0.47,0.06],10)restituito [5, 4, 1]. Dovrebbe essere [5, 5, 0].
jimmy23013,

2
Penso che sia corretto ora.
jimmy23013,

2
@CarpetPython Ho seguito un processo simile con questo algoritmo, ed è così che mi è venuto in mente questo problema. Se tolgono la tua licenza, dovrebbero prendere anche la mia :)
glebm,

4

Mathematica, 67 50 46 45 caratteri

f=(b=⌊1##⌋;b[[#~Ordering~-Tr@#&[b-##]]]++;b)&

Ungolfed:

f[s_, w_] := Module[{a = s*w, b, c, d},
  b = Floor[a];
  c = b - a;
  d = Ordering[c, -Total[c]];
  b[[d]] += 1;
  b]

Esempio:

f[5,{0.1,0.2,0.3,0.4}]

{1, 1, 1, 2}


Mio Dio, è breve, considerando che è Mathematica!
DavidC,

3

CJam - 37

q~:W,0a*\:S{[_SWf*]z::-_:e<#_2$=)t}*p

Provalo online

Spiegazione:

q~             read and evaluate the input
               (pushing the number and the array on the stack)
:W,            save the array in variable W and calculate its length (N)
0a*            make an array of N zeros (the initial "L")
\:S            swap it with the number and save the number in S
{…}*           execute the block S times
    [_SWf*]    make a matrix with 2 rows: "L" and S*W
    z          transpose the matrix, obtaining rows of [L_i S*W_i]
    ::-_       convert to array of L_i-S*W_i and duplicate
    :e<        get the smallest element
    #          find its index in the unsorted array,
               i.e. the "i" with the largest S*W_i-L_i
    _2$=)t     increment L_i
p              print the result nicely

Appunti:

  • La complessità riguarda O (S * N), quindi diventa molto lenta per S di grandi dimensioni
  • CJam è gravemente privo di operatori aritmetici per 2 array, qualcosa che ho intenzione di implementare in seguito

Idea diversa - 46

q~:Sf*_:m[_:+S\-@[1f%_,,]z{0=W*}$<{1=_2$=)t}/p

Provalo online

Questo è molto più semplice ed efficiente, ma purtroppo un po 'più a lungo. L'idea qui è di iniziare con L_i = floor (S * W_i), determinare la differenza (diciamo D) tra S e la loro somma, trovare gli indici D con la parte frazionaria più grande di S * W_i (ordinando e prendendo la D superiore) e incrementare L_i per quegli indici. Complessità O (N * log (N)).


Ora c'è la O (N) :e<.
jimmy23013,

@ user23013 oh sì, per il primo programma, grazie
aditsu smesso perché SE è MALE

È stato veloce! Congratulazioni 🌟
glebm,

Per coloro che si chiedono, la sostituzione dell'ordinamento con un algoritmo di selezione temporale lineare produrrebbe O (n) invece della O (nlogn) effettiva causata dall'ordinamento: trova l'elemento D-esimo più grande, P, in O (N), quindi incrementa elementi che sono ≥PD volte (O (N) da D <= N).
glebm,

@glebm è abbastanza bello, ma penso che ci sia un problema se più elementi hanno lo stesso valore (P). Forse puoi risolverlo in 2 passaggi: prima incrementa e conta gli elementi> P, poi sai quanti elementi = P sono necessari. O se è possibile ottenere tali informazioni dall'algoritmo di selezione, ancora meglio.
Aditsu ha smesso perché SE è MALE

3

JavaScript (ES6) 126 130 104 115 156 162 194

Dopo tutti i commenti e i casi di test nella risposta di @ CarpetPython, torniamo al mio primo algoritmo. Purtroppo, la soluzione intelligente non funziona. L'implementazione si è accorciata un po ', cerca ancora tutte le possibili soluzioni, calcola la distanza al quadrato e mantiene il minimo.

Modifica Per ogni elemento di output di peso w, 'tutti' i possibili valori sono solo 2: trunc (w * s) e trunc (w * s) +1, quindi ci sono solo (2 ** elemensts) possibili soluzioni da provare.

Q=(s,w)=>
  (n=>{
    for(i=0;
        r=q=s,(y=i++)<1<<w.length;
        q|r>n||(n=r,o=t))
      t=w.map(w=>(f=w*s,q-=d=0|f+(y&1),y/=2,f-=d,r+=f*f,d));
  })()||o

Test nella console Firefox / FireBug

;[[ 1,  [0.4, 0.3, 0.3]      ]
, [ 3,  [0, 1, 0]            ]
, [ 4,  [0.3, 0.4, 0.3]      ]
, [ 5,  [0.3, 0.4, 0.3]      ]
, [ 21, [0.3, 0.2, 0.5]      ]
, [ 5,  [0.1, 0.2, 0.3, 0.4] ]
, [ 4,  [0.11, 0.3, 0.59]    ]
, [ 10, [0.47, 0.47, 0.06]   ]
, [ 10, [0.43, 0.43, 0.14]   ]
, [ 11, [0.43, 0.43, 0.14]   ]]
.forEach(v=>console.log(v[0],v[1],Q(v[0],v[1])))

Produzione

1 [0.4, 0.3, 0.3] [1, 0, 0]
3 [0, 1, 0] [0, 3, 0]
4 [0.3, 0.4, 0.3] [1, 2, 1]
5 [0.3, 0.4, 0.3] [1, 2, 2]
21 [0.3, 0.2, 0.5] [6, 4, 11]
5 [0.1, 0.2, 0.3, 0.4] [0, 1, 2, 2]
4 [0.11, 0.3, 0.59] [1, 1, 2]
10 [0.47, 0.47, 0.06] [5, 5, 0]
10 [0.43, 0.43, 0.14] [4, 4, 2]
11 [0.43, 0.43, 0.14] [5, 5, 1]

Questa è una soluzione più intelligente. Passa singolo su array di pesi.
Per ogni passaggio trovo il valore massimo corrente in w. Cambio questo valore in posizione con il valore intero ponderato (arrotondato per eccesso), quindi se s == 21 e w = 0.4, otteniamo 0,5 * 21 -> 10,5 -> 11. Conservo questo valore negato, quindi non posso essere trovato come max nel ciclo successivo. Quindi riduco la somma totale di conseguenza (s = s-11) e riduco anche il totale dei pesi nella variabile f.
Il ciclo termina quando non è stato trovato un massimo superiore a 0 (sono stati gestiti tutti i valori! = 0).
Alla fine restituisco i valori modificati di nuovo in positivo. Avvertendo questo codice si modifica l'array dei pesi in atto, quindi deve essere chiamato con una copia dell'array originale

F=(s,w)=>
 (f=>{
  for(;j=w.indexOf(z=Math.max(...w)),z>0;f-=z)
    s+=w[j]=-Math.ceil(z*s/f);
 })(1)||w.map(x=>0-x)

Il mio primo tentativo

Non è una soluzione così intelligente. Per ogni possibile risultato, valuta la differenza e mantiene il minimo.

F=(s,w,t=w.map(_=>0),n=NaN)=>
  (p=>{
    for(;p<w.length;)
      ++t[p]>s?t[p++]=0
      :t.map(b=>r+=b,r=p=0)&&r-s||
        t.map((b,i)=>r+=(z=s*w[i]-b)*z)&&r>n||(n=r,o=[...t])
  })(0)||o

Ungolfed e spiegato

F=(s, w) =>
{
  var t=w.map(_ => 0), // 0 filled array, same size as w
      n=NaN, // initial minumum NaN, as "NaN > value"  is false for any value
      p, r
  // For loop enumerating from [1,0,0,...0] to [s,s,s...s]
  for(p=0; p<w.length;)
  {
    ++t[p]; // increment current cell
    if (t[p] > s)
    {
      // overflow, restart at 0 and point to next cell
      t[p] = 0;
      ++p;
    }
    else
    {
      // increment ok, current cell is the firts one
      p = 0;
      r = 0;
      t.map(b => r += b) // evaluate the cells sum (must be s)
      if (r==s)
      {
        // if sum of cells is s
        // evaluate the total squared distance (always offset by s, that does not matter)
        t.map((b,i) => r += (z=s*w[i]-b)*z) 
        if (!(r > n))
        {
          // if less than current mininum, keep this result
          n=r
          o=[...t] // copy of t goes in o
        }
      }
    }
  }
  return o
}

2

CJam, 48 byte

Una soluzione diretta al problema.

q~:Sf*:L,S),a*{m*{(+}%}*{1bS=},{L]z::-Yf#:+}$0=p

L'input va come

[0.3 0.4 0.3] 4

Spiegazione:

q~:S                                 "Read and parse the input, store sum in S";
    f*:L                             "Do S.W, store the dot product in L";
         S),                         "Get array of 0 to S";
        ,   a*                       "Create an array with N copies of the above array";
              {m*{(+}%}*             "Get all possible N length combinations of 0 to S ints";
                        {1bS=},      "Filter to get only those which sum up to S";
{L]z::-Yf#:+}$                       "Sort them based on (S.W_i - L_i)^2 value";
 L                                   "Put the dot product after the sum combination";
  ]z                                 "Wrap in an array and transpose";
    ::-                              "For each row, get difference, i.e. S.W_i - L_i";
       Yf#                           "Square every element";
          :+                         "Take sum";
              0=p                    "After sorting on sum((S.W_i - L_i)^2), take the";
                                     "first element, i.e. smallest sum and print it";

Provalo online qui


2

Pyth: 40 byte

Mhosm^-*Ghded2C,HNfqsTGmms+*G@Hb}bklHyUH

Questo definisce una funzione gcon 2 parametri. Puoi chiamarlo come Mhosm^-*Ghded2C,HNfqsTGmms+*G@Hb}bklHyUHg5 [0.1 0.2 0.3 0.4.

Provalo online: Pyth Compiler / Executor

Spiegazione:

mms+*G@Hb}bklHyUH     (G is S, H is the list of weights)
m             yUH    map each subset k of [0, 1, ..., len(H)-1] to:
 m          lH          map each element b of [0, 1, ..., len(H)-1] to: 
    *G@Hb                  G*H[b]
   +     }bk               + b in k
  s                       floor(_)

Questo crea tutte le possibili soluzioni L, dove L[i] = floor(S*W[i])o L[i] = floor(S*W[i]+1). Ad esempio, l'input 4 [0.3 0.4 0.3crea [[1, 1, 1], [2, 1, 1], [1, 2, 1], [1, 1, 2], [2, 2, 1], [2, 1, 2], [1, 2, 2], [2, 2, 2]].

fqsTG...  
f    ... only use the solutions, where
 qsTG       sum(solution) == G

[[2, 1, 1], [1, 2, 1], [1, 1, 2]]Resta solo .

Mhosm^-*Ghded2C,HN
  o                  order the solutions by
   s                   the sum of 
    m         C,HN       map each element d of zip(H, solution) to
     ^-*Ghded2           (G*d[0] - d[1])^2
 h                   use the first element (minimum)
M                    define a function g(G,H): return _

2

Mathematica 108

s_~f~w_:=Sort[{Tr[(s*w-#)^2],#}&/@ 
Flatten[Permutations/@IntegerPartitions[s,{Length@w},0~Range~s],1]][[1,2]]

f[3, {0, 1, 0}]
f[4, {0.3, 0.4, 0.3}]
f[5, {0.3, 0.4, 0.3}]
f[21, {0.3, 0.2, 0.5}]
f[5, {0.1, 0.2, 0.3, 0.4}]

{0, 3, 0}
{1, 2, 1}
{1, 2, 2}
{6, 4, 11}
{0, 1, 2, 2}


Spiegazione

Ungolfed

f[s_,w_]:=
Module[{partitions},
partitions=Flatten[Permutations/@IntegerPartitions[s,{Length[w]},Range[0,s]],1];
Sort[{Tr[(s *w-#)^2],#}&/@partitions][[1,2]]]

IntegerPartitions[s,{Length@w},0~Range~s]restituisce tutte le partizioni interi s, utilizzando elementi prelevati dal set {0, 1, 2, ...s}con il vincolo che l'uscita dovrebbe contenere lo stesso numero di elementi nella serie di pesi, w.

Permutations fornisce tutte le disposizioni ordinate di ciascuna partizione intera.

{Tr[(s *w-#)^2],#}restituisce un elenco di coppie ordinate, {error, permutation} per ogni permutazione.

Sort[...] ordina l'elenco di {{error1, permutation1},{error2, permutation2}...according to the size of the error.

[[1,2]]]oppure Part[<list>,{1,2}]restituisce il secondo elemento del primo elemento nell'elenco ordinato di {{error, permutation}...}. In altre parole, restituisce la permutazione con l'errore più piccolo.


2

R, 85 80 76

Utilizza il metodo Quota Hare.

Rimosso un paio dopo aver visto le specifiche che W sommerà a 1

function(a,b){s=floor(d<-b*a);s[o]=s[o<-rev(order(d%%1))[0:(a-sum(s))]]+1;s}

Prova

> (function(a,b){s=floor(d<-b/(sum(b)/a));s[o]=s[o<-rev(order(d%%1))[0:(a-sum(s))]]+1;s})(3,c(0,1,0))
[1] 0 3 0
> (function(a,b){s=floor(d<-b/(sum(b)/a));s[o]=s[o<-rev(order(d%%1))[0:(a-sum(s))]]+1;s})(1,c(0.4,0.3,0.3))
[1] 1 0 0
> (function(a,b){s=floor(d<-b/(sum(b)/a));s[o]=s[o<-rev(order(d%%1))[0:(a-sum(s))]]+1;s})(4,c(0.3, 0.4, 0.3))
[1] 1 2 1
> (function(a,b){s=floor(d<-b/(sum(b)/a));s[o]=s[o<-rev(order(d%%1))[0:(a-sum(s))]]+1;s})(5,c(0.3, 0.4, 0.3))
[1] 1 2 2
> (function(a,b){s=floor(d<-b/(sum(b)/a));s[o]=s[o<-rev(order(d%%1))[0:(a-sum(s))]]+1;s})(21,c(0.3, 0.2, 0.5))
[1]  6  4 11
> (function(a,b){s=floor(d<-b/(sum(b)/a));s[o]=s[o<-rev(order(d%%1))[0:(a-sum(s))]]+1;s})(5,c(0.1,0.2,0.3,0.4))
[1] 1 1 1 2
>

2

Python, 139 128 117 byte

def f(S,W):
 L=(S+1,0,[]),
 for n in W:L=[(x-i,y+(S*n-i)**2,z+[i])for x,y,z in L for i in range(x)]
 return min(L)[2]

Precedente soluzione itertools, 139 byte

from itertools import*
f=lambda S,W:min((sum(x)!=S,sum((S*a-b)**2for a,b in zip(W,x)),list(x))for x in product(*tee(range(S+1),len(W))))[2]

Mi chiedevo se sarebbe stata possibile una soluzione itertools. Bel lavoro +1. Ho ragione nel pensare che questo abbia O (n ^ 4) complessità temporale?
Logic Knight,

La soluzione di Itertools era in O(S^len(W))realtà: P. La nuova soluzione è molto più veloce, ma ancora lenta
Sp3000,

2

Ottava, 87 76

golfed:

function r=w(s,w)r=0*w;for(i=1:s)[m,x]=max(s*w-r);r(x)+=1;endfor endfunction

Ungolfed:

function r=w(s,w)
  r=0*w;   # will be the output
  for(i=1:s)
    [m,x]=max(s*w-r);
    r(x)+=1;
  endfor
endfunction

(Blasted "endfor" e "endfunction"! Non vincerò mai, ma mi diverto a giocare a golf con un linguaggio "reale".)


Bell'algoritmo. È possibile sostituire zeros(size(w))con 0*w.
alephalpha,

Bello! Perché non ci ho pensato?
dcsohl,

1

T-SQL, 167 265

Perché mi piace provare a fare anche queste sfide in una query.

Trasformato in una funzione incorporata per adattarsi meglio alle specifiche e creato un tipo per i dati della tabella. È costato un po ', ma questo non sarebbe mai stato un contendente. Ogni istruzione deve essere eseguita separatamente.

CREATE TYPE T AS TABLE(A INT IDENTITY, W NUMERIC(9,8))
CREATE FUNCTION W(@ int,@T T READONLY)RETURNS TABLE RETURN SELECT CASE WHEN i<=@-SUM(g)OVER(ORDER BY(SELECT\))THEN g+1 ELSE g END R,A FROM(SELECT A,ROW_NUMBER()OVER(ORDER BY (W*@)%1 DESC)i,FLOOR(W*@)g FROM @T)a

In uso

DECLARE @ INT = 21
DECLARE @T T
INSERT INTO @T(W)VALUES(0.3),(0.2),(0.5)
SELECT R FROM dbo.W(@,@T) ORDER BY A

R
---------------------------------------
6
4
11
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.