Pick a two different random elements from a given closed range I wrote a function which picks a two different random elements from a closed  range of ints and returns them as a tuple.

I would like to take a your feedback, if the solution is a "Clever", "Best practice" or "non of them"

func pickTwoRandomElementsFromRange(_ range: ClosedRange&lt;Int&gt;) -&gt; (Int, Int)? {
    guard range.count &gt;= 2 else { return nil }

    let firstElement = range.randomElement()
    var secondElement = range.randomElement()

    while firstElement == secondElement  {
        secondElement = range.randomElement()
    }
    if let firstElement = firstElement, let secondElement = secondElement {
        return (firstElement, secondElement)
    }

    return nil
}
Naming

Swift naming conventions are listed in the API Design Guidelines. With respect to “Omit needless words” and “Strive for Fluent Usage” I would suggest to call the function

func randomPair(from range: ClosedRange&lt;Int&gt;) -&gt; (Int, Int)?


Simplify the code

Your method is fine, but can be simplified a bit. First, the return values from randomElement() can safely be forced-unwrapped because it is guaranteed at that point that the range is not empty. That makes the final optional binding obsolete:

func randomPair(from range: ClosedRange&lt;Int&gt;) -&gt; (Int, Int)? {
    guard range.count &gt;= 2 else { return nil }

    let firstElement = range.randomElement()!
    var secondElement = range.randomElement()!

    while firstElement == secondElement {
        secondElement = range.randomElement()!
    }
    return (firstElement, secondElement)
}


Alternatively one can use a repeat-loop, so that the second element is assigned only at one place, that is a matter of personal preference:

func randomPair(from range: ClosedRange&lt;Int&gt;) -&gt; (Int, Int)? {
    guard range.count &gt;= 2 else { return nil }

    let firstElement = range.randomElement()!
    var secondElement: Int
    repeat {
        secondElement = range.randomElement()!
    } while firstElement == secondElement

    return (firstElement, secondElement)
}


But actually the same can be achieved without a loop, if we pick the second element from a reduced range and adjust it if necessary:

func randomPair(from range: ClosedRange&lt;Int&gt;) -&gt; (Int, Int)? {
    guard range.count &gt;= 2 else { return nil }

    let firstElement = range.randomElement()!
    var secondElement = range.dropLast().randomElement()!
    if secondElement &gt;= firstElement {
        secondElement += 1
    }

    return  (firstElement, secondElement)
}


Generalizations

Now we have a function to get a random pair from a closed range. But what about open ranges? What about ranges of other types? In fact it is not difficult to implement the same algorithm for arbitrary (random access) collections. The only difference is that we pick random indices first:

func randomPair&lt;C&gt;(from collection: C) -&gt; (C.Element, C.Element)? where C: RandomAccessCollection {
    guard collection.count &gt;= 2 else { return nil }

    let firstIndex = collection.indices.randomElement()!
    var secondIndex = collection.indices.dropLast().randomElement()!

    if secondIndex &gt;= firstIndex {
        collection.formIndex(after: &amp;secondIndex)
    }

    return (collection[firstIndex], collection[secondIndex])
}


This covers closed ranges, open ranges, arrays etc:

randomPair(from: 0...10)
randomPair(from: 0..&lt;10)
randomPair(from: ["a", "b", "c", "d"])


Alternatively one can implement this as an extension method for RandomAccessCollection so that it closely resembles the existing randomElement() method:

extension RandomAccessCollection {
    func randomPair() -&gt; (Element, Element)? {
        guard count &gt;= 2 else { return nil }

        let firstIndex = indices.randomElement()!
        var secondIndex = indices.dropLast().randomElement()!
        if secondIndex &gt;= firstIndex {
            formIndex(after: &amp;secondIndex)
        }
        return (self[firstIndex], self[secondIndex])
    }
}

(0...10).randomPair()
(0..&lt;10).randomPair()
["a", "b", "c", "d"].randomPair()