2010-10-30 2 views
3

Это компилируется и работает нормально на Visual C++ 2010 Express, но проверяется только на элемент [2]: «Рыба».Как проверить, нет ли элемента внутри вектора?

int main() 
    { 
     vector<string> words; 
     string temp; 
     vector<string> disliked(3); 
     disliked[0] = "Broccoli"; 
     disliked[1] = "Mushrooms"; 
     disliked[2] = "Fish"; 
     while (cin >> temp) 
      words.push_back(temp); 
     cout << "Number of words: " << words.size() << endl; 
     for (int i=0; i<words.size(); ++i) { 
      if (words[i]!=disliked[2]) 
       cout << words[i] << " "; 
      else cout << "BLEEP" << " "; 
     } 
     cout << endl; 
     keep_window_open(); 
     return 0; 
    } 

Как мне сделать это проверить против всех векторных элементов без ввода:

if (words[i]!=disliked[0] && words[i]!=disliked[1] && words[i]!=disliked[2]) 

? Любые другие советы о том, как сделать его лучше или элегантнее?

+1

Я случайно, как брокколи, грибы, и рыбу. – sbi

+0

Я тоже! Не беспокойтесь, это просто глупое упражнение в книге Страуструпа о программировании на C++. :) – Kensai

+0

Мне нравится грибы и рыба больше, чем брокколи. Брокколи тоже в порядке.Просто не так хорошо, как грибы и рыба. – jalf

ответ

9
if (std::find(disliked.begin(), disliked.end(), words[i]) == disliked.end()) { 
    cout << words[i] << " "; 
} else { 
    cout << "BLEEP" << " "; 
} 

Если заменить std::vector<string> disliked(3); с std::set<string> disliked; он работает быстрее.

std::set<string> disliked; 
disliked.insert("Broccoli"); 
disliked.insert("Mushrooms"); 
disliked.insert("Fish"); 
//.... 

if (disliked.find(words[i]) == disliked.end()) { 
    cout << words[i] << " "; 
} else { 
    cout << "BLEEP" << " "; 
} 
+0

+1 , просто исправьте опечатку с помощью конструктора 'std :: set'. Он не должен принимать никаких аргументов. –

+0

@Charles: Я позволил себе это исправить. – fredoverflow

1

Ну вы можете просто использовать std::find для поиска слова в векторе. Но в целом, векторы не предназначены для такого рода поиска с произвольным доступом. Возможно, вам захочется использовать std::set для хранения продуктов, которые вам не нравятся.

Тогда вы можете просто сказать:

std::set<std::string> dislike; 
dislike.insert("Broccoli"); 
dislike.insert("Mushrooms"); 
dislike.insert("Fish"); 

... 

if (dislike.find("whatever") != dislike.end()) std::cout << "BLEEP" << std::endl; 

Кроме того, рассмотреть возможность использования альтернативного ругательство на "бип".

+0

Вы говорите: «векторы не предназначены для такого рода поиска». Интересно, почему. На самом деле выражение if (words [i]! = Disliked [0,2])/* замечает, что 0 */принято и может быть запущено, но оно все равно дает мне Bleep только для Fish. – Kensai

+1

Потому что, когда вы ищете вектор для слова, вам нужно сканировать весь вектор. Это то, что фактически выполняет функция 'std :: find', что приводит к времени O (N). С помощью 'std :: set' каждый поиск - это только время работы O (Log (N)), что намного быстрее. Хотя для всего 3 предметов не будет заметной разницы. –

+1

Кроме того, что 'disliked [0,2]' не делает то, что вы думаете, что это делает. Это не означает, что вы фактически сравниваете слова 'i '' с элементами от 0 до 2 в векторе. Это просто (неправильное использование) (в основном бесполезного) оператора запятой из C. См. Http://en.wikipedia.org/wiki/Comma_operator –

0

В основном вы хотите проверить, все ли те же. Лучшая идея - использовать set. Если вам нужен вектор для чего-то другого, самым быстрым способом является сортировка вектора, прохождение его и проверка того, являются ли какие-либо последующие элементы одинаковыми (O (n log (n) + n)). Если ваши векторы невелики, ответ с 2 для циклов будет выполнять задание (O (n^2)).

1

В то время как другие методы, включая set или std :: find, на самом деле очень хорошие и быстрые,
вы должны быть в состоянии понять, как сделать это самостоятельно.
Если вы хотите проверить все элементов в words против всех элементов в disliked вы на самом деле нужны еще один for цикла.

for (std::size_t i = 0; i < words.size(); ++i) { 
    bool found = false; 
    for (std::size_t j = 0; j < disliked.size(); ++j) { 
     if (words[i] == disliked[j]) { 
      found = true; 
      break; 
     } 
     if (not found)  
     cout << words[i] << " "; 
     else 
     cout << "BLEEP" << " "; 
    } 

Это код, который вы назовете, используя std::find. Обратите внимание, что метод findstd::set использует другой подход, который часто реализуется с использованием red-black tree, который намного эффективнее.

2

C++ 0x представляет три алгоритма, которые вы можете проверить: all_of, any_of и none_of.

#include <algorithm> 
#include <functional> 

for (vector<string>::size_type i = 0; i < words.size(); ++i) 
{ 
    if (any_of(disliked.begin(), 
       disliked.end(), 
       bind2nd(equal_to<string>(), words[i]))) 
    { 
     cout << "BLEEP" << " "; 
    } 
    else 
    { 
     cout << words[i] << " "; 
    } 
} 

Но Алексей уже отмечалось, в этом конкретном случае, вы, вероятно, лучше с std::set. Вы также можете сделать binary_search на векторе, но тогда вы должны убедиться, что его отсортировали.

(Также отметим, что я изменил тип счетчика цикла от int к vector<string>::size_type.)

+0

Впечатляет! Я с нетерпением жду новых возможностей C++ 0x. – Kensai

+0

@ Kensai: Обратите внимание, что реализация 'any_of' почти тривиальна. Если ваш «впечатляющий» комментарий относится к 'bind2nd' и' equal_to', это хороший старый C++ 98. – fredoverflow

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