Получить значение повторяющихся элементов (вектор) [дубликат]

Причины, почему селекторы на основе id не работают

  1. Элемент / DOM с указанным идентификатором еще не существует.
  2. Элемент существует, но он не является зарегистрированный в DOM [в случае, если HTML-узлы динамически добавляются из ответов Ajax].
  3. Присутствует более одного элемента с тем же идентификатором, который вызывает конфликт.

Решения

  1. Попробуйте получить доступ к элементу после его объявления или, альтернативно, использовать такие вещи, как $(document).ready();
  2. . Для элементов, исходящих из ответов Ajax, используйте метод .bind() для jQuery. В старых версиях jQuery для этого было .live().
  3. Используйте инструменты [например, плагин webdeveloper для браузеров], чтобы найти дубликаты идентификаторов и удалить их.
8
задан billz 27 July 2013 в 03:31
поделиться

6 ответов

  1. Сделайте пустой std::unordered_set<std::string>
  2. Итератор вашего вектора, проверяя, является ли каждый элемент членом набора
  3. . Если он уже установлен, это duplicate, поэтому добавьте в свой список результатов
  4. В противном случае добавьте в набор.

Поскольку вы хотите, чтобы каждый дубликат был указан только один раз в результатах, вы можете использовать хешсет (а не список) для результатов.

6
ответ дан Ben Voigt 19 August 2018 в 18:10
поделиться
  • 1
    set - ужасная идея (плохая производительность). set - это когда вы вставляете динамически, что вам здесь не нужно. Так что просто sort vector и используйте unique(). – Mehrdad 27 July 2013 в 06:27
  • 2
    @Mehrdad он не выполнит задачу, которую ему нужно выполнить, чтобы подсчитывать дубликаты, а не делать вектор без дубликатов – Marina Golubtsova 27 July 2013 в 09:10
  • 3
    @MarinaGolubtsova: Я думал, что при вызове unique один раз удалить уникальные значения оставят вас с дубликатами; при вызове unique снова удаляются дубликаты, дающие вам нужный результат. Однако, похоже, unique фактически уничтожает остальную часть массива, поэтому вам нужно немного изменить что-то, чтобы заставить его работать. Однако вам все равно не нужно set. – Mehrdad 27 July 2013 в 09:21
  • 4
    @MarinaGolubtsova: См. Мой ответ ниже. – Mehrdad 27 July 2013 в 09:34
  • 5
    @Mehrdad: зависит от размера ввода. Арифметическое поведение моего решения намного лучше, чем сортировка. – Ben Voigt 27 July 2013 в 16:13

В 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));

EDIT

Объяснение решения:

  1. Сортировка вектора необходима, чтобы позднее использовать set_difference().
  2. Набор uvec автоматически сохранит отсортированные элементы и устранит дубликаты.
  3. Список output будет заполнен элементами vec - uvec.
3
ответ дан DanielKO 19 August 2018 в 18:10
поделиться

Вы можете получить довольно чистую реализацию, используя 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 кажется немного расточительным, но оно выполняет свою работу.

0
ответ дан Ethan Kaminski 19 August 2018 в 18:10
поделиться
  • 1
    хм, как вы думаете, тогда будет сложность? Я пытаюсь сохранить его под O (n ^ 2), и все это все же лучше, чем то, что я имел в виду & gt;. & Gt; – Marina Golubtsova 27 July 2013 в 01:28

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.

5
ответ дан Jerry Coffin 19 August 2018 в 18:10
поделиться
  • 1
    Такой функтор будет работать неправильно, если он будет скопирован функцией алгоритма. – jrok 27 July 2013 в 09:14
  • 2
    Ну да, вы используете операцию test-if-it-is-present-and-make-it-present . Мой ответ должен был быть руководством, а не отображением 1: 1 для вызовов функций-членов. Вы не можете сказать, что я выбрал плохие методы для деталей, когда я не дал подробностей. И existing, вероятно, должен быть unordered_set. – Ben Voigt 27 July 2013 в 16:15
  • 3
    Любой возможный счет для этого решения? – TeodorKolev 10 April 2017 в 11:52
  • 4
    @TeodorKolev: Я не уверен, что именно вы спрашиваете. Если вам нужен список уникальных слов и количество каждого из них, вы обычно используете 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 = &empty;

        for(const string& s: vec) {
                if (*prev_p==s) dup.push_back(s);
                prev_p = &s;
        }

        for(auto& w: dup) cout << w << ' '; 
        cout << '\n';
}
1
ответ дан Leonid Volnitsky 19 August 2018 в 18:10
поделиться

Вот лучший алгоритм, чем другие люди предложили:

#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 ++ и не требует, чтобы элементы были скопированы.

Если вы более умны, я думаю, вы также можете избежать сортировки вектора дважды.

0
ответ дан Mehrdad 19 August 2018 в 18:10
поделиться
  • 1
    Что делает алгоритм лучше для вас? O(N lg N), когда существует решение O(N), лучше ? – Ben Voigt 27 July 2013 в 16:21
  • 2
    @BenVoigt: (1) асимптотическая производительность, (2) эмпирическая производительность, (3) требования, предъявляемые к вызывающему абоненту (например, отсутствие необходимости в конструкторах копий, безопасность исключений), (4) потребность в вспомогательной памяти (моя не нужна для хранения копий ввода). В любом случае ваше решение также использует set, поэтому оно также O(N log N), за исключением того, что set имеет гораздо более плотную эмпирическую производительность, чем vector, что делает это решение лучше. – Mehrdad 27 July 2013 в 18:54
Другие вопросы по тегам:

Похожие вопросы: