I had the same problem. Given a set where each item has a probability and whose items' probabilities sum up to one, I wanted to draw a series of itemssample efficiently, i.e. without sorting anything and without repeatedly iterating over the setwithout sorting anything and without repeatedly iterating over the set.
The following function draws the lowest of $N$ uniformly distributed random numbers within the interval $[a,1)$. Let $r$ be a random number from $[0,1)$.
\begin{equation} \text{next}(N, a) = 1 - (1 - a) \cdot \sqrt[N]{r} \end{equation}
You can use this function to draw an ascending series $(a_i)$ of $N$ uniformly distributed random numbers in [0,1). Here is an example with $N = 10$:
$a_1 = \text{next}(10, 0)$$a_0 = \text{next}(10, 0)$
$a_2 = \text{next}(9, a_1)$$a_1 = \text{next}(9, a_0)$
$a_3 = \text{next}(8, a_2)$$a_2 = \text{next}(8, a_1)$
$\dots$
$a_{10} = \text{next}(1, a_9)$$a_9 = \text{next}(1, a_8)$
While drawing that ascending series $(a_i)$ of uniformly distributed numbers, iterate over the set of probabilities $P$ which represents your arbitraty (yet finite) distribution. Let $0 \leq k < |P|$ be the iterator and $p_k \in P$. After drawing $a_i$, increment $k$ zero or more times until $\sum p_0 \dots p_k > a_i$. Then add $p_k$ to your sample and move on with drawing $a_{i+1}$.
Example with the op's set $\{(1, 0.04), (2, 0.5), (3, 0.46)\}$ and sample size $N = 10$:
i a_i k Sum Draw
0 0.031 0 0.04 1
1 0.200 1 0.54 2
2 0.236 1 0.54 2
3 0.402 1 0.54 2
4 0.488 1 0.54 2
5 0.589 2 1.0 3
6 0.625 2 1.0 3
7 0.638 2 1.0 3
8 0.738 2 1.0 3
9 0.942 2 1.0 3
Sample: $(1, 2, 2, 2, 2, 3, 3, 3, 3, 3)$
If you wonder about the $\text{next}$ function: It is the inverse of the probability that one of $N$ uniformly distributed random numbers lies within the interval $[a, x)$ with $x \leq 1$.