How to select N unique random values that appear exactly once in an existing vector with C++

1 Answer

0 votes
#include <iostream>
#include <vector>
#include <unordered_map>
#include <algorithm>
#include <random>

/*
    Goal:
    - Select N random elements from an vector
    - Each selected element must be unique in the entire vector
      (i.e., it appears exactly once in the vector)
    - The original vector may contain duplicates, but those values
      are not eligible for selection.

    Approach:
    1. Count how many times each value appears (frequency map).
    2. Collect indices of elements whose frequency is exactly 1.
    3. Randomly sample N indices from that list.
    4. Use the indices to access and print the original values.
*/

// Build a frequency map: value -> count
std::unordered_map<int, std::size_t> buildFrequencyMap(const std::vector<int>& data) {
    std::unordered_map<int, std::size_t> freq;
    freq.reserve(data.size());

    for (int value : data) {
        ++freq[value];
    }
    
    return freq;
}

// Collect indices of elements that are unique in the whole vector (frequency == 1)
std::vector<std::size_t> collectGloballyUniqueIndices(
    const std::vector<int>& data,
    const std::unordered_map<int, std::size_t>& freq
) {
    std::vector<std::size_t> uniqueIndices;
    uniqueIndices.reserve(data.size());

    for (std::size_t i = 0; i < data.size(); ++i) {
        int value = data[i];
        // Only keep indices of values that appear exactly once in the vector
        if (freq.at(value) == 1) {
            uniqueIndices.push_back(i);
        }
    }
    return uniqueIndices;
}

// Randomly select N indices from the list of globally unique indices
std::vector<std::size_t> selectRandomUniqueIndices(
    const std::vector<std::size_t>& uniqueIndices,
    std::size_t N
) {
    // Clamp N to the number of available unique elements
    N = std::min(N, uniqueIndices.size());

    std::vector<std::size_t> result;
    result.reserve(N);

    std::random_device rd;
    std::mt19937 gen(rd());

    /*
        std::sample:
        - Random sampling without replacement
        - Perfect for selecting N distinct indices
    */
    std::sample(uniqueIndices.begin(), uniqueIndices.end(),
                std::back_inserter(result),
                N,
                gen);

    return result;
}

int main() {
    // Example vector with duplicates
    std::vector<int> data = {
        5, 12, 5, 19, 5, 33, 19, 7, 5, 8, 8, 8, 59, 61, 17, 3, 5, 3, 74, 83, 90, 3, 1
    };

    // Step 1: Build frequency map
    auto freq = buildFrequencyMap(data);

    // Step 2: Collect indices of values that are unique in the whole vector
    auto globallyUniqueIndices = collectGloballyUniqueIndices(data, freq);

    // Step 3: Choose how many unique random elements you want
    std::size_t N = 5;

    // Step 4: Randomly select N indices from the globally unique set
    auto randomIndices = selectRandomUniqueIndices(globallyUniqueIndices, N);

    // Step 5: Print all globally unique elements (for clarity)
    std::cout << "Elements that are unique in the whole vector:\n";
    for (std::size_t idx : globallyUniqueIndices) {
        std::cout << data[idx] << " ";
    }
    std::cout << "\n\nRandom selection (" << N << " elements):\n";

    // Step 6: Print the randomly selected unique elements
    for (std::size_t idx : randomIndices) {
        std::cout << data[idx] << " ";
    }
}


/*
run:

Elements that are unique in the whole vector:
12 33 7 59 61 17 74 83 90 1 

Random selection (5 elements):
12 33 17 83 1 

*/

 



answered Sep 13 by avibootz
edited Sep 13 by avibootz

Related questions

...