Как я могу использовать встроенную функцию: sort (): со структурой в c ++ [duplicate]

ECMAScript 2018 вводит группы захвата в регулярные выражения JavaScript.

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

Есть только два «структурных» преимущества названных групп захвата, о которых я могу думать:

  1. В некоторых вариантах регулярных выражений (.NET и JGSoft, насколько я знаю) , вы можете использовать одно и то же имя для разных групп в вашем регулярном выражении ( см. здесь для примера, где это имеет значение ). Но большинство разновидностей регулярных выражений в любом случае не поддерживают эту функциональность.
  2. Если вам нужно сослаться на нумерованные группы захвата в ситуации, когда они окружены цифрами, вы можете получить проблему. Предположим, вы хотите добавить нуль к цифре и, следовательно, хотите заменить (\ d) на $ 10 . В JavaScript это будет работать (до тех пор, пока в вашем регулярном выражении будет менее 10 групп захвата), но Perl подумает, что вы ищете номер обратной ссылки 10 вместо номера 1 ​​, а затем 0 . В Perl вы можете использовать $ {1} 0 в этом случае.

Кроме этого, группы захвата называются «синтаксическим сахаром». Это помогает использовать группы захвата только тогда, когда они вам действительно понадобятся, и использовать во всех других случаях не захватывающие группы (?: ...) .

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

Библиотека XRegExp Стив Левитана решает эти проблемы.

195
задан Ankur 4 September 2009 в 18:05
поделиться

12 ответов

Простой пример с использованием std::sort

struct MyStruct
{
    int key;
    std::string stringValue;

    MyStruct(int k, const std::string& s) : key(k), stringValue(s) {}
};

struct less_than_key
{
    inline bool operator() (const MyStruct& struct1, const MyStruct& struct2)
    {
        return (struct1.key < struct2.key);
    }
};

std::vector < MyStruct > vec;

vec.push_back(MyStruct(4, "test"));
vec.push_back(MyStruct(3, "a"));
vec.push_back(MyStruct(2, "is"));
vec.push_back(MyStruct(1, "this"));

std::sort(vec.begin(), vec.end(), less_than_key());

Редактирование: как указывал Кирилл В. Лядвинский, вместо предоставления предиката сортировки вы можете реализовать operator< для MyStruct:

struct MyStruct
{
    int key;
    std::string stringValue;

    MyStruct(int k, const std::string& s) : key(k), stringValue(s) {}

    bool operator < (const MyStruct& str) const
    {
        return (key < str.key);
    }
};

Используя этот метод, вы можете просто отсортировать вектор следующим образом:

std::sort(vec.begin(), vec.end());

Edit2: Как говорит Каппа, вы также можете сортируйте вектор в порядке убывания, перегрузив оператор > и изменив вызов сортировки бит:

struct MyStruct
{
    int key;
    std::string stringValue;

    MyStruct(int k, const std::string& s) : key(k), stringValue(s) {}

    bool operator > (const MyStruct& str) const
    {
        return (key > str.key);
    }
};

И вы должны вызвать сортировку как:

std::sort(vec.begin(), vec.end(),greater<MyStruct>());
300
ответ дан Ron 17 August 2018 в 10:38
поделиться
  • 1
    Не могли бы вы объяснить, почему вы сделали функцию сравнения в строке struct less_than_key (в первом) примере? – kluka 15 May 2013 в 19:10
  • 2
    и другой вопрос / примечание: если вы хотите иметь несколько методов сортировки (для разных атрибутов) в классе, способ перегрузки & lt; оператор, вероятно, не вариант, не так ли? – kluka 15 May 2013 в 19:28
  • 3
    Самое интересное - предоставить оператора & gt; метод. Это позволит нам сортировать в обратном порядке, например: std::sort(vec.begin(), vec.end(), greater<MyStruct>()), который является чистым и элегантным. – kappa 31 May 2014 в 00:21
  • 4
    @Bovaz Вам нужно #include <functional> использовать & quot; std :: greater & quot ;. – Nick Hartung 31 August 2015 в 15:21
  • 5
    @kappa: где вы могли бы просто использовать operator< и использовать либо std::sort(vec.begin(), vec.end());, либо std::sort(vec.rbegin(), vec.rend()); в зависимости от того, хотите ли вы иметь восходящий или нисходящий порядок. – Pixelchemist 19 May 2016 в 22:24
    // sort algorithm example
    #include <iostream>     // std::cout
    #include <algorithm>    // std::sort
    #include <vector>       // std::vector
    using namespace std;
    int main () {
        char myints[] = {'F','C','E','G','A','H','B','D'};
        vector<char> myvector (myints, myints+8);               // 32 71 12 45 26 80 53 33
        // using default comparison (operator <):
        sort (myvector.begin(), myvector.end());           //(12 32 45 71)26 80 53 33
        // print out content:
        cout << "myvector contains:";
        for (int i=0; i!=8; i++)
            cout << ' ' <<myvector[i];
        cout << '\n';
        system("PAUSE");
    return 0;
    }
1
ответ дан Amin Alomaisi 17 August 2018 в 10:38
поделиться
typedef struct Freqamp{
    double freq;
    double amp;
}FREQAMP;

bool struct_cmp_by_freq(FREQAMP a, FREQAMP b)
{
    return a.freq < b.freq;
}

main()
{
    vector <FREQAMP> temp;
    FREQAMP freqAMP;

    freqAMP.freq = 330;
    freqAMP.amp = 117.56;
    temp.push_back(freqAMP);

    freqAMP.freq = 450;
    freqAMP.amp = 99.56;
    temp.push_back(freqAMP);

    freqAMP.freq = 110;
    freqAMP.amp = 106.56;
    temp.push_back(freqAMP);

    sort(temp.begin(),temp.end(), struct_cmp_by_freq);
}

, если сравнение ложно, оно будет «обмениваться».

0
ответ дан bruce 17 August 2018 в 10:38
поделиться

Мне было любопытно, есть ли какое-либо измеримое влияние на производительность между различными способами вызова std :: sort, поэтому я создал этот простой тест:

$ cat sort.cpp
#include<algorithm>
#include<iostream>
#include<vector>
#include<chrono>

#define COMPILER_BARRIER() asm volatile("" ::: "memory");

typedef unsigned long int ulint;

using namespace std;

struct S {
  int x;
  int y;
};

#define BODY { return s1.x*s2.y < s2.x*s1.y; }

bool operator<( const S& s1, const S& s2 ) BODY
bool Sgreater_func( const S& s1, const S& s2 ) BODY

struct Sgreater {
  bool operator()( const S& s1, const S& s2 ) const BODY
};

void sort_by_operator(vector<S> & v){
  sort(v.begin(), v.end());
}

void sort_by_lambda(vector<S> & v){
  sort(v.begin(), v.end(), []( const S& s1, const S& s2 ) BODY );
}

void sort_by_functor(vector<S> &v){
  sort(v.begin(), v.end(), Sgreater());
}

void sort_by_function(vector<S> &v){
  sort(v.begin(), v.end(), &Sgreater_func);
}

const int N = 10000000;
vector<S> random_vector;

ulint run(void foo(vector<S> &v)){
  vector<S> tmp(random_vector);
  foo(tmp);
  ulint checksum = 0;
  for(int i=0;i<tmp.size();++i){
     checksum += i *tmp[i].x ^ tmp[i].y;
  }
  return checksum;
}

void measure(void foo(vector<S> & v)){

ulint check_sum = 0;

  // warm up
  const int WARMUP_ROUNDS = 3;
  const int TEST_ROUNDS = 10;

  for(int t=WARMUP_ROUNDS;t--;){
    COMPILER_BARRIER();
    check_sum += run(foo);
    COMPILER_BARRIER();
  }

  for(int t=TEST_ROUNDS;t--;){
    COMPILER_BARRIER();
    auto start = std::chrono::high_resolution_clock::now();
    COMPILER_BARRIER();
    check_sum += run(foo);
    COMPILER_BARRIER();
    auto end = std::chrono::high_resolution_clock::now();
    COMPILER_BARRIER();
    auto duration_ns = std::chrono::duration_cast<std::chrono::duration<double>>(end - start).count();

    cout << "Took " << duration_ns << "s to complete round" << endl;
  }

  cout << "Checksum: " << check_sum << endl;
}

#define M(x) \
  cout << "Measure " #x " on " << N << " items:" << endl;\
  measure(x);

int main(){
  random_vector.reserve(N);

  for(int i=0;i<N;++i){
    random_vector.push_back(S{rand(), rand()});
  }

  M(sort_by_operator);
  M(sort_by_lambda);
  M(sort_by_functor);
  M(sort_by_function);
  return 0;
}

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

Я компилировал с g ++ (GCC ) 7.2.1 20170829 (Red Hat 7.2.1-1)

$ g++ -O2 -o sort sort.cpp && ./sort

Вот результаты:

Measure sort_by_operator on 10000000 items:
Took 0.994285s to complete round
Took 0.990162s to complete round
Took 0.992103s to complete round
Took 0.989638s to complete round
Took 0.98105s to complete round
Took 0.991913s to complete round
Took 0.992176s to complete round
Took 0.981706s to complete round
Took 0.99021s to complete round
Took 0.988841s to complete round
Checksum: 18446656212269526361
Measure sort_by_lambda on 10000000 items:
Took 0.974274s to complete round
Took 0.97298s to complete round
Took 0.964506s to complete round
Took 0.96899s to complete round
Took 0.965773s to complete round
Took 0.96457s to complete round
Took 0.974286s to complete round
Took 0.975524s to complete round
Took 0.966238s to complete round
Took 0.964676s to complete round
Checksum: 18446656212269526361
Measure sort_by_functor on 10000000 items:
Took 0.964359s to complete round
Took 0.979619s to complete round
Took 0.974027s to complete round
Took 0.964671s to complete round
Took 0.964764s to complete round
Took 0.966491s to complete round
Took 0.964706s to complete round
Took 0.965115s to complete round
Took 0.964352s to complete round
Took 0.968954s to complete round
Checksum: 18446656212269526361
Measure sort_by_function on 10000000 items:
Took 1.29942s to complete round
Took 1.3029s to complete round
Took 1.29931s to complete round
Took 1.29946s to complete round
Took 1.29837s to complete round
Took 1.30132s to complete round
Took 1.3023s to complete round
Took 1.30997s to complete round
Took 1.30819s to complete round
Took 1.3003s to complete round
Checksum: 18446656212269526361

Похоже, что все параметры, кроме передатчика функции, очень аналогично, и передача указателя функции вызывает + 30% штраф.

Он также выглядит как оператор & lt; версия на ~ 1% медленнее (я повторял тест несколько раз, и эффект сохраняется), что немного странно, так как предполагает, что сгенерированный код отличается (мне не хватает навыков для анализа --save-temps output).

0
ответ дан Chris Reid 17 August 2018 в 10:38
поделиться

В вашем классе вы можете перегрузить символ "& lt;" оператора.

class MyClass
{
  bool operator <(const MyClass& rhs)
  {
    return this->key < rhs.key;
  }
}
120
ответ дан Corvusoft 17 August 2018 в 10:38
поделиться
  • 1
    дополнительный +1 для включения #includes – Anne 3 May 2016 в 17:35
  • 2
    Чтобы быть ясным, это приводит к возрастанию; используйте > вместо <, чтобы получить убывающий порядок. – bhaller 27 April 2017 в 04:53

Вы можете использовать функтор в качестве третьего аргумента std::sort, или вы можете определить operator< в своем классе.

struct X {
    int x;
    bool operator<( const X& val ) const { 
        return x < val.x; 
    }
};

struct Xgreater
{
    bool operator()( const X& lx, const X& rx ) const {
        return lx.x < rx.x;
    }
};

int main () {
    std::vector<X> my_vec;

    // use X::operator< by default
    std::sort( my_vec.begin(), my_vec.end() );

    // use functor
    std::sort( my_vec.begin(), my_vec.end(), Xgreater() );
}
52
ответ дан Kirill V. Lyadvinsky 17 August 2018 в 10:38
поделиться
  • 1
    зачем нам добавлять const в конце сигнатуры функции? – prongs 14 June 2013 в 12:40
  • 2
    Функция не изменяет объект, поэтому он const. – Kirill V. Lyadvinsky 2 July 2013 в 09:35
  • 3
    Если это так, то почему мы передаем «const X & amp; val ", я предполагаю, что передача значения as const в функцию заставляет функцию думать, что ее значение не будет изменено. – Prashant Bhanarkar 22 August 2016 в 06:47
  • 4
    @PrashantBhanarkar Ключевое слово const в конце подписи указывает, что функция operator() не изменяет экземпляр структуры Xgreater (которая обычно может иметь переменные-члены), тогда как указание const для входных значений только указывает, что эти входные значения неизменяемы. – schester 28 December 2017 в 20:35

Да, std::sort() с третьим параметром (функцией или объектом) было бы проще. Пример: http://www.cplusplus.com/reference/algorithm/sort/

4
ответ дан Manos Nikolaidis 17 August 2018 в 10:38
поделиться
  • 1
    Не совсем ссылка только ответ, но, по крайней мере, один пример строки был бы полезен. – Manos Nikolaidis 31 December 2015 в 12:20

Сортировка такого vector или любого другого применимого (изменяемого входного итератора) диапазона пользовательских объектов типа X может быть достигнута с использованием различных методов, особенно включая использование стандартных библиотечных алгоритмов, таких как

Поскольку большинство методов для получения относительного упорядочения элементов X уже были опубликованы, Я начну с некоторых заметок о «почему» и «когда» использовать различные подходы.

«Лучший» подход будет зависеть от разных факторов:

  1. диапазон сортировки объектов X - обычная или редкая задача (будут ли эти диапазоны отсортированы в разных местах в программе или пользователями библиотеки)?
  2. Требуется ли сортировка «естественная» (ожидаемая) или Есть ли несколько способов сравнить тип с самим собой?
  3. Является ли производительность проблемой или должны ли диапазоны сортировки объектов X быть безупречными?

Если sor диапазоны ting X являются общей задачей, и ожидаемая сортировка должна ожидаться (т. X просто обертывает одно фундаментальное значение), тогда он, вероятно, перейдет на перегрузку operator<, поскольку он позволяет сортировать без каких-либо fuzz (например, правильно передавать соответствующие компараторы) и многократно дает ожидаемые результаты.

Если сортировка общая задача или может потребоваться в разных контекстах, но есть несколько критериев, которые можно использовать для сортировки объектов X, я бы пошел на функторы (перегруженные функции operator() пользовательских классов) или указатели на функции (то есть один функтор / функция для лексического упорядочения и еще один для естественного упорядочения).

Если диапазоны сортировки типа X являются необычными или маловероятными в других контекстах, я стараюсь использовать лямбда вместо того, чтобы загромождать любое пространство имен с большим количеством функций или типы.

Это особенно верно, если сортировка не является «понятной» или «естественной». Вы можете легко получить логику заказа, глядя на лямбду, которая применяется на месте, тогда как operator< - это противостояние с первого взгляда, и вам нужно будет найти определение, чтобы знать, какая логика упорядочения будет применена.

Обратите внимание, однако, что одно определение operator< является единственной точкой отказа, тогда как несколько lambas являются множественными точками отказа и требуют большей осторожности.

Если определение operator< isn 't, если сортировка выполнена / шаблон сортировки скомпилирован, компилятору может быть предложено вызвать вызов функции при сравнении объектов, вместо того, чтобы встраивать логику упорядочения, которая может быть серьезным недостатком (по крайней мере, когда оптимизация / код времени ссылки генерация не применяется).

Способы достижения сопоставимости class X для использования стандартных алгоритмов сортировки библиотек

Пусть std::vector<X> vec_X; и std::vector<Y> vec_Y;

] 1. Перегрузка T::operator<(T) или operator<(T, T) и использование стандартных шаблонов библиотек, которые не ожидают функции сравнения.

Любой элемент перегрузки operator<:

struct X {
  int i{}; 
  bool operator<(X const &r) const { return i < r.i; } 
};
// ...
std::sort(vec_X.begin(), vec_X.end());

или free operator< :

struct Y {
  int j{}; 
};
bool operator<(Y const &l, Y const &r) { return l.j < r.j; }
// ...
std::sort(vec_Y.begin(), vec_Y.end());

2. Использовать указатель функции с пользовательской функцией сравнения в качестве параметра функции сортировки.

struct X {
  int i{};  
};
bool X_less(X const &l, X const &r) { return l.i < r.i; }
// ...
std::sort(vec_X.begin(), vec_X.end(), &X_less);

3. Создайте перегрузку bool operator()(T, T) для настраиваемого типа, который может быть передан как функтор сравнения.

struct X {
  int i{};  
  int j{};
};
struct less_X_i
{
    bool operator()(X const &l, X const &r) const { return l.i < r.i; }
};
struct less_X_j
{
    bool operator()(X const &l, X const &r) const { return l.j < r.j; }
};
// sort by i
std::sort(vec_X.begin(), vec_X.end(), less_X_i{});
// or sort by j
std::sort(vec_X.begin(), vec_X.end(), less_X_j{});

Эти определения объектов функций могут быть написаны немного более общие с использованием C ++ 11 и шаблонов:

struct less_i
{ 
    template<class T, class U>
    bool operator()(T&& l, U&& r) const { return std::forward<T>(l).i < std::forward<U>(r).i; }
};

, который можно использовать для сортировки любого типа с элементом i, поддерживающим <.

4. Передайте закрытие анонима (лямбда) в качестве параметра сравнения к функциям сортировки.

struct X {
  int i{}, j{};
};
std::sort(vec_X.begin(), vec_X.end(), [](X const &l, X const &r) { return l.i < r.i; });

В тех случаях, когда C ++ 14 допускает еще более общее лямбда-выражение:

std::sort(a.begin(), a.end(), [](auto && l, auto && r) { return l.i < r.i; });

, которое может быть обернуто в макрос

#define COMPARATOR(code) [](auto && l, auto && r) -> bool { return code ; }

, что делает обычное создание компаратора совершенно гладким:

// sort by i
std::sort(v.begin(), v.end(), COMPARATOR(l.i < r.i));
// sort by j
std::sort(v.begin(), v.end(), COMPARATOR(l.j < r.j));
10
ответ дан Pixelchemist 17 August 2018 в 10:38
поделиться
  • 1
    В 2. случае, когда вы написали bool X_less(X const &l, X const &r) const { return l.i < r.i; } для компаратора, но ключевые слова const должны быть удалены (поскольку это не функция-член). – PolGraphic 29 August 2016 в 17:43
  • 2
    @PolGraphic: Правильно - и в случае 1. – Pixelchemist 29 August 2016 в 21:45
  • 3
    @Pixelchemist, как бы я использовал (4.) лямбда-подход, когда не использовал std::sort или аналогичный, но нуждался в экземпляре Compare, например. при создании экземпляра std::set? – azrdev 28 March 2018 в 13:56
  • 4
    @azrdev: шаблон функции, который фиксирует тип замыкания, чтобы передать его как параметр шаблона для установки: template<class T, class C> std::set<T, C> make_set(C const& compare) { return std::set<T, C>{ compare }; }, который можно использовать как auto xset = make_set<X>([](auto && l, auto && r) { return l.i < r.i; });. – Pixelchemist 29 March 2018 в 19:19

Вы на правильном пути. std::sort будет использовать operator< в качестве функции сравнения по умолчанию. Поэтому для сортировки ваших объектов вам придется либо перегрузить bool operator<( const T&, const T& ), либо предоставить функтор, который выполняет сравнение, например:

 struct C {
    int i;
    static bool before( const C& c1, const C& c2 ) { return c1.i < c2.i; }
 };

 bool operator<( const C& c1, const C& c2 ) { return c1.i > c2.i; }

 std::vector<C> values;

 std::sort( values.begin(), values.end() ); // uses operator<
 std::sort( values.begin(), values.end(), C::before );

. Преимущество использования функтора заключается в том, что вы можете использовать функцию с доступом к частным членам класса.

12
ответ дан pjvandehaar 17 August 2018 в 10:38
поделиться
  • 1
    Пропущено это: предоставить оператор-член-член & lt ;. – xtofl 4 September 2009 в 18:13
  • 2
    Лучше сделать operator< членом класса (или структуры), потому что глобальный может использовать защищенные или частные члены. Или вы должны сделать его другом структуры C. – Kirill V. Lyadvinsky 4 September 2009 в 18:25

Чтобы отсортировать вектор, вы можете использовать алгоритм sort ().

sort(vec.begin(),vec.end(),less<int>());

Третий используемый параметр может быть больше или меньше, или любая функция или объект также могут использоваться. Однако оператор по умолчанию равен & lt; если вы оставите третий параметр пустым.

// using function as comp
std::sort (myvector.begin()+4, myvector.end(), myfunction);
bool myfunction (int i,int j) { return (i<j); }

// using object as comp
std::sort (myvector.begin(), myvector.end(), myobject);
0
ответ дан Prashant Shubham 17 August 2018 в 10:38
поделиться

Ниже приведен код с использованием lambdas

#include "stdafx.h"
#include <vector>
#include <algorithm>

using namespace std;

struct MyStruct
{
    int key;
    std::string stringValue;

    MyStruct(int k, const std::string& s) : key(k), stringValue(s) {}
};

int main()
{
    std::vector < MyStruct > vec;

    vec.push_back(MyStruct(4, "test"));
    vec.push_back(MyStruct(3, "a"));
    vec.push_back(MyStruct(2, "is"));
    vec.push_back(MyStruct(1, "this"));

    std::sort(vec.begin(), vec.end(), 
        [] (const MyStruct& struct1, const MyStruct& struct2)
        {
            return (struct1.key < struct2.key);
        }
    );
    return 0;
}
2
ответ дан Sathwick 17 August 2018 в 10:38
поделиться

Вы можете использовать определенный пользователем класс компаратора.

class comparator
{
    int x;
    bool operator()( const comparator &m,  const comparator &n )
    { 
       return m.x<n.x;
    }
 }
1
ответ дан user 17 August 2018 в 10:38
поделиться
Другие вопросы по тегам:

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