Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ get index of element of array by value

So far, I have been storing the array in a vector and then looping through the vector to find the matching element and then returning the index.

Is there a faster way to do this in C++? The STL structure I use to store the array doesn't really matter to me (it doesn't have to be a vector). My array is also unique (no repeating elements) and ordered (e.g. a list of dates going forward in time).

like image 544
user788171 Avatar asked Jul 07 '12 22:07

user788171


People also ask

How do you find the index of an array of elements?

JavaScript Array findIndex() The findIndex() method executes a function for each array element. The findIndex() method returns the index (position) of the first element that passes a test. The findIndex() method returns -1 if no match is found.

How do I find the index of a specific element?

To find the index of an element in a list, you use the index() function. It returns 3 as expected. However, if you attempt to find an element that doesn't exist in the list using the index() function, you'll get an error. To fix this issue, you need to use the in operator.

How do I print the index of an array?

You can access an array element using an expression which contains the name of the array followed by the index of the required element in square brackets. To print it simply pass this method to the println() method.

Is there an indexOf for arrays?

IndexOf(Array, Object, Int32) Searches for the specified object in a range of elements of a one-dimensional array, and returns the index of its first occurrence. The range extends from a specified index to the end of the array.


2 Answers

Since the elements are sorted, you can use a binary search to find the matching element. The C++ Standard Library has a std::lower_bound algorithm that can be used for this purpose. I would recommend wrapping it in your own binary search algorithm, for clarity and simplicity:

/// Performs a binary search for an element
///
/// The range `[first, last)` must be ordered via `comparer`.  If `value` is
/// found in the range, an iterator to the first element comparing equal to
/// `value` will be returned; if `value` is not found in the range, `last` is
/// returned.
template <typename RandomAccessIterator, typename Value, typename Comparer>
auto binary_search(RandomAccessIterator const  first,
                   RandomAccessIterator const  last,
                   Value                const& value,
                   Comparer                    comparer) -> RandomAccessIterator
{
    RandomAccessIterator it(std::lower_bound(first, last, value, comparer));
    if (it == last || comparer(*it, value) || comparer(value, *it))
        return last;

    return it;
}

(The C++ Standard Library has a std::binary_search, but it returns a bool: true if the range contains the element, false otherwise. It's not useful if you want an iterator to the element.)

Once you have an iterator to the element, you can use std::distance algorithm to compute the index of the element in the range.

Both of these algorithms work equally well any random access sequence, including both std::vector and ordinary arrays.

like image 184
James McNellis Avatar answered Oct 10 '22 02:10

James McNellis


If you want to associate a value with an index and find the index quickly you can use std::map or std::unordered_map. You can also combine these with other data structures (e.g. a std::list or std::vector) depending on the other operations you want to perform on the data.

For example, when creating the vector we also create a lookup table:

vector<int> test(test_size);
unordered_map<int, size_t> lookup;
int value = 0;
for(size_t index = 0; index < test_size; ++index)
{
    test[index] = value;
    lookup[value] = index;
    value += rand()%100+1;
}

Now to look up the index you simply:

size_t index = lookup[find_value];

Using a hash table based data structure (e.g. the unordered_map) is a fairly classical space/time tradeoff and can outperform doing a binary search for this sort of "reverse" lookup operation when you need to do a lot of lookups. The other advantage is that it also works when the vector is unsorted.

For fun :-) I've done a quick benchmark in VS2012RC comparing James' binary search code with a linear search and with using unordered_map for lookup, all on a vector: Performance of various find index methods

To ~50000 elements unordered_set significantly (x3-4) outpeforms the binary search which is exhibiting the expected O(log N) behavior, the somewhat surprising result is that unordered_map loses it's O(1) behavior past 10000 elements, presumably due to hash collisions, perhaps an implementation issue.

EDIT: max_load_factor() for the unordered map is 1 so there should be no collisions. The difference in performance between the binary search and the hash table for very large vectors appears to be caching related and varies depending on the lookup pattern in the benchmark.

Choosing between std::map and std::unordered_map talks about the difference between ordered and unordered maps.

like image 7
Guy Sirton Avatar answered Oct 10 '22 03:10

Guy Sirton