Paradoxe de répartition


10

Donné:

  • Un nombre naturel S .
  • Une liste de N poids rationnels W qui totalisent 1.

Renvoie une liste L de N entiers non négatifs, tels que:

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

En d'autres termes, rapprochez le plus possible S⋅W_is de nombres entiers.

Exemples:

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]

Règles:

  • Vous pouvez utiliser n'importe quel format d'entrée ou simplement fournir une fonction qui accepte l'entrée comme arguments.

Contexte:

Ce problème survient lors de l'affichage de S de différents types d'articles dans différentes proportions W i en ce qui concerne les types.

Un autre exemple de ce problème est la représentation politique proportionnelle, voir le paradoxe de la répartition . Les deux derniers cas de test sont connus sous le nom de paradoxe de l'Alabama.

En tant que statisticien, j'ai reconnu ce problème comme équivalent à un problème rencontré dans l'identification des tailles d'échantillon lors de la réalisation d'un échantillon stratifié. Dans cette situation, nous voulons que la proportion de chaque strate dans l'échantillon soit égale à la proportion de chaque strate dans la population. - @tomi


Pourriez-vous dire en mots quelle est la tâche? J'ai du mal à décompresser les expressions en quelque chose d'intuitif.
xnor

Les deux doivent être ≤, fixes. La tâche consiste à présenter un entier sous la forme d'une somme d'entiers basée sur des poids. Le reste devrait être réparti en privilégiant les poids les plus élevés, bien que je ne sois pas sûr que cette exigence soit codée correctement? Ceci est intéressant car round(A + B) != round(A) + round(B), une solution courte nécessite un aperçu de ce qui se passe ici.
glebm

1
Peut-être changer les règles pour minimiser la somme des distances au L[i] - S*W[i]carré, au lieu de la règle 2 et la règle 3. Ce serait approximatif S*W[i].
Jakube

1
Est également [0 1 2 2] une autre solution possible pour5 [0.1 0.2 0.3 0.4]
Jakube

1
Vous devriez peut-être ajouter un exemple pour 1 [0,4 0,3 0,3]
aditsu quitter car SE est EVIL

Réponses:


6

APL, 21

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

Ceci est une traduction de la réponse CJam d' Aditsu de 37 octets .

Testez-le en ligne .

Explication

 {      ⍵-⍺}            ⍝ 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

Mon premier (et deuxième) (et troisième) algorithme a eu des problèmes donc après une (une autre!) Réécriture et plus de tests, voici (j'espère vraiment) une solution correcte et rapide:

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 source avant le minificateur ressemble maintenant à:

# 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

Les tests renvoient:

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

Cet algorithme est similaire à d'autres réponses ici. C'est O (1) pour num, donc il a le même temps d'exécution pour les entiers 10 et 1000000. C'est théoriquement O (nlogn) pour le nombre de poids (à cause du tri). Si cela résiste à tous les autres cas d'entrée délicats, il remplacera l'algorithme ci-dessous dans ma boîte à outils de programmation.

Veuillez ne pas utiliser cet algorithme avec quoi que ce soit qui ne soit pas du golf. J'ai fait des compromis de vitesse pour minimiser la taille de la source. Le code suivant utilise la même logique mais est beaucoup plus rapide et plus 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

La valeur de num n'affecte pas la vitesse de manière significative. Je l'ai testé avec des valeurs de 1 à 10 ^ 19. Le temps d'exécution varie linéairement avec le nombre de poids. Sur mon ordinateur, cela prend 0,15 seconde avec 10 ^ 5 poids et 15 secondes avec 10 ^ 7 poids. Notez que les poids ne sont pas limités aux fractions qui totalisent un. La technique de tri utilisée ici est également environ deux fois plus rapide que le sorted((v,i) for i,v in enumerate...)style traditionnel .

Algorithme d'origine

C'était une fonction de ma boîte à outils, légèrement modifiée pour le golf. C'était à l'origine d'une réponse SO . Et c'est faux.

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

Il donne une approximation, mais n'est pas toujours correct, bien que la somme (outseq) == num soit maintenue. Rapide mais non recommandé.

Merci à @alephalpha et @ user23013 pour avoir repéré les erreurs.

EDIT: définissez totalw (d) sur 1 car OP spécifie que la somme des poids sera toujours 1. Maintenant 83 octets.

EDIT2: correction d'un bug trouvé pour [0.4, 0.3, 0.3], 1.

EDIT3: Algorithme défectueux abandonné. Ajout d'un meilleur.

EDIT4: Cela devient ridicule. Remplacé par un algorithme correct (j'espère vraiment).

EDIT5: Ajout d'un code non-golfique pour les autres qui aimeraient utiliser cet algorithme.


4
a([0.4, 0.3, 0.3], 1)renvoie [0, 1, 0], tandis que la bonne réponse est [1, 0, 0].
alephalpha

1
Toujours incorrecte. a([0.11,0.3,0.59],4)retourné [0, 1, 3]. Devrait l'être [1, 1, 2].
jimmy23013

1
f([0.47,0.47,0.06],10)retourné [5, 4, 1]. Devrait l'être [5, 5, 0].
jimmy23013

2
Je pense que c'est correct maintenant.
jimmy23013

2
@CarpetPython J'ai suivi un processus similaire avec cet algorithme, et c'est ainsi que j'ai trouvé ce problème. S'ils vous enlèvent votre licence, ils devraient aussi prendre la mienne :)
glebm

4

Mathematica, 67 50 46 45 caractères

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

Non golfé:

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]

Exemple:

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

{1, 1, 1, 2}


Mon Dieu, c'est court, vu que c'est Mathematica!
DavidC

3

CJam - 37

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

Essayez-le en ligne

Explication:

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

Remarques:

  • La complexité est d'environ O (S * N), donc cela devient vraiment lent pour les grands S
  • CJam manque cruellement d'opérateurs arithmétiques pour 2 tableaux, quelque chose que je prévois de mettre en œuvre plus tard

Idée différente - 46

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

Essayez-le en ligne

C'est beaucoup plus simple et efficace, mais hélas, un peu plus long. L'idée ici est de commencer par L_i = plancher (S * W_i), de déterminer la différence (disons D) entre S et leur somme, de trouver les indices D avec la plus grande partie fractionnelle de S * W_i (en triant et en prenant D en haut) et incrémenter L_i pour ces indices. Complexité O (N * log (N)).


Maintenant, il y a le O (N) :e<.
jimmy23013

@ user23013 oh ouais, pour le premier programme, merci
aditsu quitte parce que SE est EVIL le

C'était rapide! Félicitations 🌟
glebm

Pour ceux qui se demandent, remplacer le tri par un algorithme de sélection de temps linéaire produirait O (n) au lieu du O réel (nlogn) provoqué par le tri: Trouvez le D-ème plus grand élément, P, dans O (N), puis incrémentez éléments qui sont ≥PD fois (O (N) depuis D <= N).
glebm

@glebm c'est plutôt cool, mais je pense qu'il y a un problème si plusieurs éléments ont la même valeur (P). Peut-être que vous pouvez le résoudre en 2 passes: incrémentez d'abord et comptez les éléments> P, puis vous savez combien d'éléments = P sont nécessaires. Ou si vous pouvez obtenir ces informations de l'algorithme de sélection, c'est encore mieux.
aditsu quitte car SE est EVIL le

3

JavaScript (ES6) 126 130 104 115 115 156 162 194

Après tous les commentaires et cas de test dans la réponse de @ CarpetPython, revenons à mon premier algorithme. Hélas, la solution intelligente ne fonctionne pas. Mise en œuvre un peu raccourcie, elle essaie toujours toutes les solutions possibles, calcule la distance au carré et garde le minimum.

Modifier Pour chaque élément de sortie de poids w, `` toutes '' les valeurs possibles ne sont que 2: trunc (w * s) et trunc (w * s) +1, il n'y a donc que (2 ** elemensts) solutions possibles à essayer.

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

Tester dans la 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])))

Production

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]

C'est une solution plus intelligente. Un seul passage sur le tableau de poids.
Pour chaque passe, je trouve la valeur maximale actuelle en w. Je change cette valeur en place avec la valeur entière pondérée (arrondie vers le haut), donc si s == 21 et w = 0,4, nous obtenons 0,5 * 21 -> 10,5 -> 11. Je stocke cette valeur niée, donc elle ne peut pas être trouvé comme max dans la boucle suivante. Ensuite, je réduis la somme totale en conséquence (s = s-11) et réduit également le total des poids dans la variable f.
La boucle se termine lorsqu'il n'y a pas de max au dessus de 0 à trouver (toutes les valeurs! = 0 ont été gérées).
Enfin, je renvoie à nouveau les valeurs changées en positif. Attention ce code modifie le tableau de poids en place, il doit donc être appelé avec une copie du tableau d'origine

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)

Mon premier essai

Pas si une solution intelligente. Pour chaque résultat possible, il évalue la différence et garde le minimum.

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

Non golfé et expliqué

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 octets

Une solution simple au problème.

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

L'entrée va comme

[0.3 0.4 0.3] 4

Explication:

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";

Essayez-le en ligne ici


2

Pyth: 40 octets

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

Ceci définit une fonction gavec 2 paramètres. Vous pouvez l'appeler comme Mhosm^-*Ghded2C,HNfqsTGmms+*G@Hb}bklHyUHg5 [0.1 0.2 0.3 0.4.

Essayez-le en ligne: Pyth Compiler / Executor

Explication:

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(_)

Cela crée toutes les solutions possibles L, où L[i] = floor(S*W[i])ou L[i] = floor(S*W[i]+1). Par exemple, l'entrée 4 [0.3 0.4 0.3crée [[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

Reste seulement [[2, 1, 1], [1, 2, 1], [1, 1, 2]].

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}


Explication

Non golfé

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]renvoie toutes les partitions entiers de s, en utilisant des éléments pris dans l'ensemble {0, 1, 2, ...s}avec la contrainte que la sortie doit contenir le même nombre d'éléments que dans l'ensemble de poids, w.

Permutations donne tous les arrangements ordonnés de chaque partition entière.

{Tr[(s *w-#)^2],#}renvoie une liste de paires ordonnées, {error, permutation} pour chaque permutation.

Sort[...] trie la liste des {{error1, permutation1},{error2, permutation2}...according to the size of the error.

[[1,2]]]ou Part[<list>,{1,2}]renvoie le deuxième élément du premier élément de la liste triée de {{error, permutation}...}. En d'autres termes, il renvoie la permutation avec la plus petite erreur.


2

R, 85 80 76

Utilise la méthode Hare Quota.

Suppression d'un couple après avoir vu la spécification selon laquelle W sera égal à 1

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

Essai

> (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 octets

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]

Solution itertools précédente, 139 octets

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]

Je me demandais si une solution itertools serait possible. Beau travail +1. Ai-je raison de penser que cela a une complexité temporelle O (n ^ 4)?
Logic Knight

La solution Itertools était en O(S^len(W))fait: P. La nouvelle solution est beaucoup plus rapide, mais toujours lente
Sp3000

2

Octave, 87 76

Golfé:

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

Non golfé:

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

("Endfor" et "endfunction" fous! Je ne gagnerai jamais mais j'aime jouer au golf avec un "vrai" langage.)


Bel algorithme. Vous pouvez remplacer zeros(size(w))par 0*w.
alephalpha

Agréable! Pourquoi n'y ai-je pas pensé?
dcsohl

1

T-SQL, 167 265

Parce que j'aime aussi essayer de relever ces défis dans une requête.

Le transforma en une fonction en ligne pour mieux s'adapter aux spécifications et créa un type pour les données de la table. Cela a coûté un peu, mais cela n'allait jamais être un concurrent. Chaque instruction doit être exécutée séparément.

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

Utilisé

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
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.