Weighted Probability Problem in Swift
There is one error in your implementation: The test
if rand &lt;= range must be if rand &lt; range, otherwise the returned 
values are not correctly distributed according to the given weights.
You can check that with the input list

[("Red", 1), ("Blue", 1)]


which returns only "Red" without this fix.

Apart from that, your code looks correct, but there are some
possible improvements.


The final return "" is never reached unless you made a programming
error. Instead of returning some value (in order to satisfy the compiler), replace it by

fatalError("This should never be reached")


This will stop the program execution immediately, and
fatalError() has the @noreturn attribute, so the compiler won't
complain about a missing return value.
Replace for tuple in input { } by for (color, weight) in input,
that allows you to get rid of the non-descriptive tuple.0 and tuple.1
in the loop body.
Add the current weight to the sum before testing against rand,
that makes the range variable obsolete.


The function does then look like this:

func weightedColor(input: [(String, Int)]) -&gt; String {

    let total = UInt32(input.map { $0.1 }.reduce(0, combine: +))
    let rand = Int(arc4random_uniform(total))

    var sum = 0
    for (color, weight) in input {
        sum += weight
        if rand &lt; sum {
            return color
        }
    }

    fatalError("This should never be reached")
}


The next step is to make the function generic. 
There is nothing which is special to colors or strings,
so you can simply replace String by a generic type T:

func weightedRandomElement&lt;T&gt;(items: [(T, Int)]) -&gt; T {

    let total = UInt32(items.map { $0.1 }.reduce(0, combine: +))
    let rand = Int(arc4random_uniform(total))

    var sum = 0
    for (element, weight) in items {
        sum += weight
        if rand &lt; sum {
            return element
        }
    }

    fatalError("This should never be reached")
}


Then the same function can be used to get a random color:

let colors = [("Red", 20), ("Blue", 50), ("Green", 70)]
let color = weightedRandomElement(colors)


or a random number:

let numbers = [(3.1415, 20), (2.71827, 50)]
let number = weightedRandomElement(numbers)


or anything else.



Update: As @hashemi correctly said, the fatalError() point would 
also be reached if the function is called with an empty array.
Actually that would also happen if the function is called with a non-empty array but the sum of the given weights is zero. These
situations could be considered as a programming error on the caller's side and can be checked with a  precondition().

@hashemi also suggested to use UInt instead of Int as data type
for the weights. This is more natural because the weights must not
be negative (and unexpected results would happen for negative input).

Then the function looks like this:

func weightedRandomElement&lt;T&gt;(items: [(T, UInt)]) -&gt; T {

    let total = items.map { $0.1 }.reduce(0, combine: +)
    precondition(total &gt; 0, "The sum of the weights must be positive")

    let rand = UInt(arc4random_uniform(UInt32(total)))

    var sum = UInt(0)
    for (element, weight) in items {
        sum += weight
        if rand &lt; sum {
            return element
        }
    }

    fatalError("This should never be reached")
}


and is called like

let colors : [(String, UInt)] = [("Red", 20), ("Blue", 50), ("Green", 70)]
let color = weightedRandomElement(colors)