2009-09-15 3 views
32

мне нужно найти позицию элемента в станд :: вектор, чтобы использовать его для ссылки на элемент в другой вектор:Как найти позицию элемента в std :: vector?

int find(const vector<type>& where, int searchParameter) 
{ 
    for(int i = 0; i < where.size(); i++) { 
     if(conditionMet(where[i], searchParameter)) { 
      return i; 
     } 
    } 
    return -1; 
} 
// caller: 
const int position = find(firstVector, parameter); 
if(position != -1) { 
    doAction(secondVector[position]); 
} 

однако vector::size() возвращает size_t, который соответствует unsigned интегрального типа, который не может прямое хранение -1. Как я могу сигнализировать, что элемент не найден в векторе при использовании size_t вместо int в качестве индекса?

+8

Я думаю, что название вопроса должно быть изменено. Проблема заключается не в том, как найти позицию элемента, а о ссылках на элементы в двух векторах. –

+0

Ну, если проблема составляет около -1, посмотрите [здесь] (http://www.cplusplus.com/reference/climits/), или вы можете использовать 'return (size_t) -1;' – ST3

ответ

14

Вы можете использовать std::numeric_limits<size_t>::max() для элементов, которые не были найдены. Это допустимое значение, но создать контейнер с таким максимальным индексом невозможно. Если std::vector имеет размер, равный std::numeric_limits<size_t>::max(), то максимально допустимый индекс будет (std::numeric_limits<size_t>::max()-1), так как элементы отсчитываются от 0.

56

Ознакомьтесь с ответами на этот вопрос: Invalid value for size_t?. Также вы можете использовать std :: find_if с std :: distance, чтобы получить индекс.

std::vector<type>::iterator iter = std::find_if(vec.begin(), vec.end(), comparisonFunc); 
size_t index = std::distance(vec.begin(), iter); 
if(index == vec.size()) 
{ 
    //invalid 
} 
+7

Или вы можете проверить итератор против 'where.end()', и вычислить/использовать расстояние, если оно не равно. Не влияет на производительность, просто проверяет успех сразу после вызова, чтобы найти. –

1

Возможно, вы не должны использовать свою функцию здесь. Используйте find() от STL.

Пример:

 
list L; 
L.push_back(3); 
L.push_back(1); 
L.push_back(7);

list::iterator result = find(L.begin(), L.end(), 7); assert(result == L.end() || *result == 7);

+1

Ему нужно передать итератор другому вектору. – GManNickG

+0

Yeap, это точно моя проблема. Итератор будет в порядке, но я не могу напрямую использовать его с другим вектором. – sharptooth

3

В этом случае можно смело откинуть неподписанную часть, если ваш вектор не может получить действительно большим.

Я бы вытащил where.size() в локальную переменную, так как она не будет меняться во время вызова. Что-то вроде этого:

int find(const vector<type>& where, int searchParameter){ 
    int size = static_cast<int>(where.size()); 
    for(int i = 0; i < size; i++) { 
     if(conditionMet(where[i], searchParameter)) { 
      return i; 
     } 
    } 
    return -1; 
} 
17

Прежде всего, вам действительно нужно хранить такие индексы? Вы заглянули в std :: map, позволяя вам хранить пары ключ => значение?

Во-вторых, если вы использовали итераторы вместо этого, вы можете вернуть std :: vector.end(), чтобы указать неверный результат. Чтобы преобразовать итератор в индекс, вы просто используете

size_t i = it - myvector.begin(); 
2

Что-то вроде этого, я думаю. find_if_counted.hpp:

#ifndef FIND_IF_COUNTED_HPP 
#define FIND_IF_COUNTED_HPP 

#include <algorithm> 

namespace find_if_counted_impl 
{ 
    template <typename Func> 
    struct func_counter 
    { 
     explicit func_counter(Func& func, unsigned &count) : 
     _func(func), 
     _count(count) 
     { 
     } 

     template <typename T> 
     bool operator()(const T& t) 
     { 
      ++_count; 

      return _func(t); 
     } 

    private: 
     Func& _func; 
     unsigned& _count; 
    }; 
} 

// generic find_if_counted, 
// returns the index of the found element, otherwise returns find_if_not_found 
const size_t find_if_not_found = static_cast<size_t>(-1); 

template <typename InputIterator, typename Func> 
size_t find_if_counted(InputIterator start, InputIterator finish, Func func) 
{ 
    unsigned count = 0; 
    find_if_counted_impl::func_counter<Func> f(func, count); 

    InputIterator result = find_if(start, finish, f); 

    if (result == finish) 
    { 
     return find_if_not_found; 
    } 
    else 
    { 
     return count - 1; 
    } 
} 

#endif 

Пример:

#include "find_if_counted.hpp" 
#include <cstdlib> 
#include <iostream> 
#include <vector> 

typedef std::vector<int> container; 

int rand_number(void) 
{ 
    return rand() % 20; 
} 

bool is_even(int i) 
{ 
    return i % 2 == 0; 
} 

int main(void) 
{ 
    container vec1(10); 
    container vec2(10); 

    std::generate(vec1.begin(), vec1.end(), rand_number); 
    std::generate(vec2.begin(), vec2.end(), rand_number); 

    unsigned index = find_if_counted(vec1.begin(), vec1.end(), is_even); 

    if (index == find_if_not_found) 
    { 
     std::cout << "vec1 has no even numbers." << std::endl; 
    } 
    else 
    { 
     std::cout << "vec1 had an even number at index: " << index << 
      " vec2's corresponding number is: " << vec2[index] << std::endl; 
    } 
} 

Хотя я чувствую, что я делаю что-то глупо ...: X Любые поправки приветствуются, конечно.

+0

Несколько глупость - вещь find_if_counted_impl. :) Если у вас нет итератора с произвольным доступом, индекс практически бесполезен для начала. Если у вас есть итератор с произвольным доступом, вы можете просто вычесть found_it - begin(). Мне также кажется, что возвращаемый размер(), поскольку значение «не найден» может быть более полезным, например, вы можете быть уверены, что begin() + size() дает итератор, который может быть полезен для некоторых целей, тогда как begin() + unsigned (-1) никогда не делает ничего хорошего и обязательно должен быть проверен специально. – UncleBens

6

std::vector имеют итераторы с произвольным доступом. Вы можете сделать с ними арифметику указателей. В частности, это всегда имеет значение my_vec.begin() + my_vec.size() == my_vec.end(). Таким образом, вы могли бы сделать

const vector<type>::const_iterator pos = std::find_if(firstVector.begin() 
                , firstVector.end() 
                , some_predicate(parameter)); 
if(position != firstVector.end()) { 
    const vector<type>::size_type idx = pos-firstVector.begin(); 
    doAction(secondVector[idx]); 
} 

В качестве альтернативы, всегда есть std::numeric_limits<vector<type>::size_type>::max() использоваться как недействительное значение.

2

Если у вектора есть N элементов, для поиска есть N + 1 возможных ответов. std :: find и std :: find_if возвращают итератор найденному элементу OR end(), если элемент не найден.Для того, чтобы изменить код как можно меньше, ваша функция должна вернуть находку эквивалентную позицию:

size_t find(const vector<type>& where, int searchParameter) 
{ 
    for(size_t i = 0; i < where.size(); i++) { 
     if(conditionMet(where[i], searchParameter)) { 
      return i; 
     } 
    } 
    return where.size(); 
} 
// caller: 
const int position = find(firstVector, parameter); 
if(position != secondVector.size()) { 
    doAction(secondVector[position]); 
} 

Я бы еще использовать зЬй :: find_if, хотя.

+0

+1 для возврата 'where.size()'. Это имеет смысл вернуть его. Это согласуется с философией возврата 'where.end()', если функция должна была возвращать итератор. – Nawaz

1

Возьмите вектор целого и ключа (который мы найдем в векторе) .... Теперь мы перемещаем вектор до тех пор, пока не найдем значение ключа или последний индекс (иначе) ..... Если мы найдем ключ, тогда напечатайте позицию, иначе напечатайте «-1».

 #include <bits/stdc++.h> 
    using namespace std; 

    int main() 
     { 
      vector<int>str; 
      int flag,temp key, ,len,num; 

      flag=0; 
      cin>>len; 

      for(int i=1; i<=len; i++) 
      { 
       cin>>key; 
       v.push_back(key); 
      } 

      cin>>num; 

      for(int i=1; i<=len; i++) 
      { 
      if(str[i]==num) 
      { 
       flag++; 
       temp=i-1; 
       break; 
      } 
      } 

     if(flag!=0) cout<<temp<<endl; 
     else   cout<<"-1"<<endl; 
     str.clear(); 

     return 0; 
     } 
+1

, пожалуйста, объясните свой код в своем сообщении. –

+1

Возьмите массив целых чисел и ключ (который мы найдем в массиве) .... Теперь мы пересекаем индекс массива, пока не найдем значение ключа или последний индекс ..... Если бы мы нашли затем распечатайте индекс, иначе напечатайте «-1». – rashedcs

+0

@rashedcs, пожалуйста, отредактируйте свой ответ, чтобы включить то, что вы написали как комментарий! –

Смежные вопросы