Причины, почему селекторы на основе id не работают
Решения
$(document).ready();
.bind()
для jQuery. В старых версиях jQuery для этого было .live()
. std::unordered_set<std::string>
Поскольку вы хотите, чтобы каждый дубликат был указан только один раз в результатах, вы можете использовать хешсет (а не список) для результатов.
В 3 строках (не считая создания вектора и списка, а также лишних разрывов строк в названии читаемости):
vector<string> vec{"words", "words", "are", "fun", "fun"};
sort(vec.begin(), vec.end());
set<string> uvec(vec.begin(), vec.end());
list<string> output;
set_difference(vec.begin(), vec.end(),
uvec.begin(), uvec.end(),
back_inserter(output));
Объяснение решения:
set_difference()
. uvec
автоматически сохранит отсортированные элементы и устранит дубликаты. output
будет заполнен элементами vec - uvec
. Вы можете получить довольно чистую реализацию, используя std :: map, чтобы подсчитать вхождения, а затем полагаться на std :: list :: sort, чтобы отсортировать полученный список слов. Например:
std::list<std::string> duplicateWordList(const std::vector<std::string>& words) {
std::map<std::string, int> temp;
std::list<std::string> ret;
for (std::vector<std::string>::const_iterator iter = words.begin(); iter != words.end(); ++iter) {
temp[*iter] += 1;
// only add the word to our return list on the second copy
// (first copy doesn't count, third and later copies have already been handled)
if (temp[*iter] == 2) {
ret.push_back(*iter);
}
}
ret.sort();
return ret;
}
Использование std :: map кажется немного расточительным, но оно выполняет свою работу.
IMO, Ben Voigt начал с хорошей базовой идеи, но я бы предостерег от его формулировки слишком буквально.
В частности, мне не нравится идея поиска строки в наборе, а затем добавление это к вашему набору, если его нет, и добавив его в вывод, если он присутствует. Это в основном означает, что каждый раз, когда мы сталкиваемся с новым словом, мы дважды ищем наш набор существующих слов, один раз, чтобы проверить, присутствует ли слово, и снова вставить его, потому что это не так. Большая часть этого поиска будет по существу идентичной - если какой-то другой поток не изменяет структуру в промежуточный период (что может привести к состоянию гонки).
Вместо этого я начал с попытки добавить его к набору слов, которые вы видели. Это возвращает pair<iterator, bool>
, а bool
установлен на true
тогда и только тогда, когда значение было вставлено - то есть ранее не было. Это позволяет нам консолидировать поиск существующей строки и вставить новую строку вместе в одну вставку:
while (input >> word)
if (!(existing.insert(word)).second)
output.insert(word);
Это также очищает поток настолько, что довольно легко включить тест в функтор, который мы можем использовать с std::remove_copy_if
, чтобы получить наши результаты совершенно напрямую:
#include <set>
#include <iterator>
#include <algorithm>
#include <string>
#include <vector>
#include <iostream>
class show_copies {
std::set<std::string> existing;
public:
bool operator()(std::string const &in) {
return existing.insert(in).second;
}
};
int main() {
std::vector<std::string> words{ "words", "words", "are", "fun", "fun" };
std::set<std::string> result;
std::remove_copy_if(words.begin(), words.end(),
std::inserter(result, result.end()), show_copies());
for (auto const &s : result)
std::cout << s << "\n";
}
В зависимости от того, насколько я больше заботился о простоте или скорости выполнения кода, я мог бы использовать std::vector
вместо set
для результата и используйте std::sort
, а затем std::unique_copy
, чтобы получить окончательный результат. В таком случае я, вероятно, также заменил бы std::set
внутри show_copies
на std::unordered_set
:
#include <unordered_set>
#include <iterator>
#include <algorithm>
#include <string>
#include <vector>
#include <iostream>
class show_copies {
std::unordered_set<std::string> existing;
public:
bool operator()(std::string const &in) {
return existing.insert(in).second;
}
};
int main() {
std::vector<std::string> words{ "words", "words", "are", "fun", "fun" };
std::vector<std::string> intermediate;
std::remove_copy_if(words.begin(), words.end(),
std::back_inserter(intermediate), show_copies());
std::sort(intermediate.begin(), intermediate.end());
std::unique_copy(intermediate.begin(), intermediate.end(),
std::ostream_iterator<std::string>(std::cout, "\n"));
}
Это немного сложнее (одна целая линия длиннее!), Но, вероятно, быть значительно быстрее, когда / если количество слов становится очень большим. Также обратите внимание, что я использую std::unique_copy
в первую очередь для получения видимого вывода. Если вы хотите получить результат в коллекции, вы можете использовать стандартную уникальную / стирающую идиому для получения уникальных элементов в intermediate
.
existing
, вероятно, должен быть unordered_set
.
– Ben Voigt
27 July 2013 в 16:15
map<string, int>
. Прочитайте слова и увеличьте количество для каждого. Затем пройдите по карте и выпишите слова и счет для каждого.
– Jerry Coffin
10 April 2017 в 14:30
На месте (без дополнительного хранилища). Нет строкового копирования (кроме списка результатов). Один сорт + один проход:
#include <string>
#include <vector>
#include <list>
#include <iostream>
#include <algorithm>
using namespace std;
int main() {
vector<string> vec{"words", "words", "are", "fun", "fun"};
list<string> dup;
sort(vec.begin(), vec.end());
const string empty{""};
const string* prev_p = ∅
for(const string& s: vec) {
if (*prev_p==s) dup.push_back(s);
prev_p = &s;
}
for(auto& w: dup) cout << w << ' ';
cout << '\n';
}
Вот лучший алгоритм, чем другие люди предложили:
#include <algorithm>
#include <vector>
template<class It> It unique2(It const begin, It const end)
{
It i = begin;
if (i != end)
{
It j = i;
for (++j; j != end; ++j)
{
if (*i != *j)
{ using std::swap; swap(*++i, *j); }
}
++i;
}
return i;
}
int main()
{
std::vector<std::string> v;
v.push_back("words");
v.push_back("words");
v.push_back("are");
v.push_back("fun");
v.push_back("words");
v.push_back("fun");
v.push_back("fun");
std::sort(v.begin(), v.end());
v.erase(v.begin(), unique2(v.begin(), v.end()));
std::sort(v.begin(), v.end());
v.erase(unique2(v.begin(), v.end()), v.end());
}
Это лучше, потому что для хранения требуется только swap
без вспомогательного vector
, что означает, что он будет вести себя оптимально для более ранних версиях C ++ и не требует, чтобы элементы были скопированы.
Если вы более умны, я думаю, вы также можете избежать сортировки вектора дважды.
O(N lg N)
, когда существует решение O(N)
, лучше i>?
– Ben Voigt
27 July 2013 в 16:21
set
, поэтому оно также O(N log N)
, за исключением того, что set
имеет гораздо более плотную эмпирическую производительность, чем vector
, что делает это решение лучше.
– Mehrdad
27 July 2013 в 18:54
set
- ужасная идея (плохая производительность).set
- это когда вы вставляете динамически, что вам здесь не нужно. Так что простоsort
vector
и используйтеunique()
. – Mehrdad 27 July 2013 в 06:27unique
один раз удалить i> уникальные значения оставят вас с дубликатами; при вызовеunique
снова удаляются дубликаты, дающие вам нужный результат. Однако, похоже,unique
фактически уничтожает i> остальную часть массива, поэтому вам нужно немного изменить что-то, чтобы заставить его работать. Однако вам все равно не нужноset
. – Mehrdad 27 July 2013 в 09:21