Упорядочивать два вектора с sort ()

В упражнении Программинг Принсиплес and Практисе Усинг C ++ они просят упорядочивать два вектора; одно из имен и другой возрастов, и в конце концов они должны совпадать. Например:

У меня есть 2 вектора:

vector<string> nombres;
vector<double> edades;

И наполнив вектора с push_back, () я получаю следующий вывод:

(María, 19)
(Arturo, 12)
(José, 20)
(Chabelo, 1000)

Когда (имена) используют функцию sort, я получаю:

(Arturo, 19)
(Chabelo, 12)
(José, 20)
(María, 1000)

И если я также использую sort (возрасты), я получаю:

(Arturo, 12)
(Chabelo, 19)
(José, 20)
(María, 1000)

Мой вопрос: Как я могу использовать функцию sort () с вектором назови, чтобы производить следующее:

(Arturo, 12)
(Chabelo, 1000)
(José, 20)
(María, 19)
2
задан 29.12.2016, 10:36
0 ответов

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

Первое, из-за удобства, состоит в том, чтобы предоставлять характерную форму, чтобы сравнивать элементы главного вектора. В этом случае характерный метод попробует упорядочивать элементы используя действующий "несовершеннолетний, что":

template<class T>
struct DefaultFuncComparar
{
  bool operator()(T const& a, T const& b)
  {
    return a < b;
  }
};

И сейчас функция распорядка:

template<class T, class U, class FuncComparar = std::function<bool(T const&, T const&)>>
void OrdenarVectores(
  std::vector<T>& a,
  std::vector<U>& b,
  FuncComparar comparar = DefaultFuncComparar<T>())
{
  std::vector<T> copiaA{a};
  std::vector<U> copiaB{b};

  // Creamos el vector de índices
  std::vector<std::size_t> vector_indices(a.size());
  std::iota(vector_indices.begin(), vector_indices.end(), 0);

  // Ordenamos los índices en base al vector "a"
  std::sort(vector_indices.begin(), vector_indices.end(),
      [&](std::size_t i, std::size_t j){ return comparar(a[i], a[j]); });

  // Ordenamos los vectores "a" y "b" en base al vector de índices
  std::transform(vector_indices.begin(), vector_indices.end(), a.begin(),
      [&](std::size_t i){ return copiaA[i]; });

  std::transform(vector_indices.begin(), vector_indices.end(), b.begin(),
      [&](std::size_t i){ return copiaB[i]; });
}

Если мы сейчас это тестируем со следующим кодом:

int main(){
  std::vector<std::string> nombres = { "Maria", "Arturo", "Jose", "Chabelo" };
  std::vector<int> edades = { 19, 12, 20, 1000 };

  OrdenarVectores(nombres,edades);

  std::cout << "Ordenados por nombre\n";
  for( unsigned i=0u; i<nombres.size(); i++)
  {
    std::cout << edades[i] << ' ' << nombres[i] << '\n';
  }
  std::cout << '\n';

  OrdenarVectores(edades,nombres);

  std::cout << "Ordenados por edad\n";
  for( unsigned i=0u; i<nombres.size(); i++)
  {
    std::cout << edades[i] << ' ' << nombres[i] << '\n';
  }
}

Результат - следующий:

Ordenados por nombre
12 Arturo
1000 Chabelo
20 Jose
19 Maria

Ordenados por edad
12 Arturo
19 Maria
20 Jose
1000 Chabelo

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

2
ответ дан 03.12.2019, 17:56

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

Строить вектор пар:

std::vector< std::pair< string, int> > nombreEdad;
for (size_t n=0; n<nombres.size(); ++n)
    nombreEdad.push_back( std::pair<string,int>(nombres[n], edades[n]));

Comparador в средство:

struct nombreMenor
{
    inline bool operator() (std::pair<string,int>& p1, 
                            const std::pair<string,int>& p2)
    {
        return p1.first.compare( p2.first) < 0;
    }
};

Он позвонит в sort с comparador в средство.

std::sort(nombreEdad.begin(), nombreEdad.end(), nombreMenor());    

Печатать результат.

for( auto par : nombreEdad )
    std::cout << par.first << "," << par.second << std::endl;
1
ответ дан 03.12.2019, 17:56

Я хотел бы добавить к уже существующим решениям версию с шаблонами variádicas

Предложение.

template <std::size_t INDEX, typename TUPLE>
void push(const TUPLE &) {}

template <std::size_t INDEX, typename TUPLE, typename T, typename ... TYPES>
void push(const TUPLE &tupla, std::vector<T> &t, std::vector<TYPES> &...args)
{
    t.push_back(std::get<INDEX>(tupla));
    push<INDEX + 1>(tupla, args ...);
}

template <typename T>
T pop(std::vector<T> &v)
{
    auto t = v.back();
    v.pop_back();
    return t;
}

template <typename T, typename ... TYPES>
void ordena(std::vector<T> &t, std::vector<TYPES> &...args)
{
    using tupla = std::tuple<T, TYPES ...>;
    std::vector<tupla> valores(t.size());

    std::generate(valores.begin(), valores.end(), [&]() -> tupla
    {
        return { pop(t), pop(args)... };
    });

    std::sort(valores.begin(), valores.end(), [](auto i, auto d)
    {
        return std::get<0>(i) < std::get<0>(d);
    });

    for (const auto &valor : valores)
    {
        push<0>(valor, t, args...);
    }
}

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

Объяснение.

Функция упорядочивает, что он получает между 1 и infinitos2 вектора любого типа ordenable и упорядочивает все их с порядком первого полученного вектора:

template <typename T, typename ... TYPES>
void ordena(std::vector<T> &t, std::vector<TYPES> &...args)

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

Первое, что делается, состоит в том, чтобы создавать tupla всех типов векторов, чтобы создавать вектор с этим tupla и упорядочивать всю стоимость одновременно:

using tupla = std::tuple<T, TYPES ...>;
std::vector<tupla> valores(t.size());

Расширив шаблон с векторами nombres и edades функция ordena это осталось бы так:

void ordena(std::vector<std::string> &t, std::vector<double> &p0)
{
    using tupla = std::tuple<std::string, double>;
    std::vector<tupla> valores(t.size());
    ...

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

std::vector<std::string> s;
std::vector<double> d;
std::vector<int> i;
std::vector<char> c;

ordena(s, d, i, c);

Он расширился бы в:

void ordena(std::vector<std::string> &t, std::vector<double> &p0, std::vector<int> &p1, std::vector<char> &p2)
{
    using tupla = std::tuple<std::string, double, int, char>;
    std::vector<tupla> valores(t.size());
    ...

Seguidamente предохраняет в векторе tuplas каждую из стоимости от первоначальных векторов, одновременно, что опустошают первоначальные вектора, это получают с std::generate используя lambda:

std::generate(valores.begin(), valores.end(), [&]() -> tupla
{
    return { pop(t), pop(args)... };
});

Эта инструкция, используя последний пример expandería следующего способа:

std::generate(valores.begin(), valores.end(), [&]() -> tupla
{
    return { pop(t), pop(p0), pop(p1), pop(p2) };
});

Мы звоним в generate с lambda, тип которого возврата - tupla шаблона instanciada, так что мы будем добавлять элементы, соединенные парами всех элементов в том же положении во всех векторах, перемещенных за параметр, в наш случай он вектор valores вслед за вызовом в generate он остался бы:

valores 0: <María,   19>
valores 1: <Arturo,  12>
valores 2: <José,    20>
valores 3: <Chabelo, 1000>

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

Далее рукоположен tupla valores используя первый элемент tupla (посредством функции std::get<0>):

std::sort(valores.begin(), valores.end(), [](auto i, auto d)
{
    return std::get<0>(i) < std::get<0>(d);
});

И чтобы заканчиваться, мы используем функцию перекурсивный вспомогательный шаблон push:

for (const auto &valor : valores)
{
    push<0>(valor, t, args...);
}

Что в примере nombres и edades он расширился бы так:

push<0>(const std::tuple<std::string, double> &tupla, std::vector<std::string> &t, std::vector<double> &p0)
{
    t.push_back(std::get<0>(tupla));
    push<1>(tupla, p0);
}

push<1>(const std::tuple<std::string, double> &tupla, std::vector<double> &t)
{
    t.push_back(std::get<1>(tupla));
    push<2>(tupla);
}

push<2>(const std::tuple<std::string, double> &tupla) {}

Так что функция ordena смоги быть использованным так:

int main()
{
    std::vector<std::string> nombres = {"María", "Arturo", "José", "Chabelo"};
    std::vector<double> edades = {19, 12, 20, 1000};

    ordena(nombres, edades);

    return 0;
}

Упорядочивая nombres и edades так:

| nombres | edades |
+---------+--------+
| Arturo  | 12     |
| Chabelo | 1000   |
| José    | 20     |
| María   | 19     |

И позволь упорядочивать с cualquier2 количество векторов:

std::vector<std::string> nombres = {"María", "Arturo", "José", "Chabelo"};
std::vector<double> edades = {19, 12, 20, 1000};
std::vector<double> numeros { 3.1415, 1.11, 2.22, 1e6 };

ordena(numeros, edades, nombres);

Образец:

| numeros | edades | nombres |
+---------+--------+---------+
| 1.11    | 19     | María   |
| 2.22    | 20     | José    |
| 3.1415  | 12     | Arturo  |
| 1e+06   | 1000   | Chabelo |

[Здесь] ты можешь видеть код функционируя. Имей в виду, что код понимает, что все вектора - того же размера, и что он дорогой на уровне перепоселения памяти.


1Borra источника и копии в судьбе, он не использует семантику движения.

2Infinitos не: столькие, поскольку позволил составитель.

2
ответ дан 03.12.2019, 17:56

Упражнение требовало создавать функцию, которая упорядочивала оба вектора - я это путал с функцией sort () - Решение, которое я осуществил, было следующим (где возраст и имя - вектора, которые уже были наполнены в другой функции программы):

void Ordenar(){
    vector<string> cp_nom = nombre;     
    sort(nombre);
    vector<double> cp_edad;     
    for(int i = 0; i < nombre.size(); ++i){
        for(int j = 0; j < cp_nom.size(); ++j){
            if(cp_nom[j] == nombre[i]){
                cp_edad.push_back(edad[j]);
            }
        }
    }           
    edad.clear();
    edad = cp_edad;
}

Где я верю в копию вектора, назовите вектор <string> cp_nom, которую я использую, чтобы подтверждать положения первоначального вектора вектор <string> имя, уже упорядоченное с функцией sort () и так я начинаю наполнять вектор <double> cp_edad, когда контент вектора заканчивает замену <double> возраст с контентом вектора <double> cp_edad

1
ответ дан 03.12.2019, 17:56