Avatar billede petersteph Nybegynder
23. oktober 2004 - 00:42 Der er 12 kommentarer og
1 løsning

STL sort med keys og items

Hvis man har en array eller STL-vector a kan man sortere den med:
std::sort(a,a+len);

Mit spørgsmål er: hvis man har to arrays key og item, og gerne vil sortere dem begge (hvor key bestemmer rækkefølgen). Hvordan gør man det med STL?
Avatar billede bertelbrander Novice
23. oktober 2004 - 00:50 #1
Måske:

#include <iostream>
#include <algorithm>
#include <vector>

class StoreClass
{
public:
  StoreClass(std::string aName, int aVal) : Name(aName), Val(aVal)
  {}

  std::string Name;
  int Val;
};

class CompareClass
{
public:
  bool operator () (const StoreClass &lhs, const StoreClass &rhs)
  {
      return lhs.Name < rhs.Name;
  }
};

std::vector<StoreClass > MyVector;

int main()
{
  MyVector.push_back(StoreClass("Ole",    12));
  MyVector.push_back(StoreClass("Anders", 21));
  MyVector.push_back(StoreClass("Peter",  32));

  std::vector<StoreClass >::size_type i;
  for(i = 0; i < MyVector.size(); i++)
      std::cout << MyVector[i].Name << " " << MyVector[i].Val << std::endl;

  CompareClass Compare;
  std::sort(MyVector.begin(), MyVector.end(), Compare);

  for(i = 0; i < MyVector.size(); i++)
      std::cout << MyVector[i].Name << " " << MyVector[i].Val << std::endl;
}
Avatar billede bertelbrander Novice
23. oktober 2004 - 01:08 #2
Jeg kender ikke en metode til at sortere to arrays/vectors/containers på een gang.
Avatar billede bertelbrander Novice
23. oktober 2004 - 02:07 #3
Man kunne måske også:

#include <iostream>
#include <algorithm>
#include <vector>
#include <map>
#include <string>

std::vector<std::string > MyVector1;
std::vector<int  > MyVector2;

int main()
{
  MyVector1.push_back("Ole");
  MyVector1.push_back("Anders");
  MyVector1.push_back("Peter");
  MyVector2.push_back(12);
  MyVector2.push_back(1);
  MyVector2.push_back(3);

  std::map<std::string, int> Temp;

  std::vector<std::string >::size_type i;
  for(i = 0;  i <  MyVector1.size(); i++)
      Temp.insert(std::make_pair(MyVector1[i], MyVector2[i]));

  MyVector1.clear();
  MyVector2.clear();

  std::map<std::string, int>::iterator it;
  for(it = Temp.begin(); it != Temp.end(); ++it)
  {
      MyVector1.push_back(it->first);
      MyVector2.push_back(it->second);
  }

  for(i = 0; i < MyVector1.size(); i++)
      std::cout << MyVector1[i] << " " << MyVector2[i] << std::endl;
}
Avatar billede petersteph Nybegynder
23. oktober 2004 - 10:56 #4
Mange tak!
Avatar billede petersteph Nybegynder
23. oktober 2004 - 10:58 #5
Jeg er ny her. Hvordan giver jeg dig dine 30 points?
Avatar billede bertelbrander Novice
23. oktober 2004 - 15:25 #6
Man kan ikke give point til kommentarer, kun til svar.
Men jeg vil ikke have point, så jeg laver ikke svar.
Hvis du har fået løst dit problem, laver du selv et svar som du derpå accepterer, så får du pointene tilbage.
Avatar billede petersteph Nybegynder
23. oktober 2004 - 16:43 #7
:)
Avatar billede arne_v Ekspert
23. oktober 2004 - 20:16 #8
Hvis betingelsen er at man skal bruge std::sort, så har Bertel på glimrende vis
beskrvet mulighederne.

Men jeg mener ikke at det er smart at brueg std::sort i dette tilfælde. Man kan
sagtens løse opgaven uden brug af nye STL strukturer, hvis man er villig
til selv at skrive sorterings algoritmen.

To eksempler:

#include <iostream>
#include <string>
#include <cstdlib>
#include <ctime>

using namespace std;

template<class T>
void qsix(int n1,int n2,T *a,int *ix)
{
  int l=n1;
  int r=n2;
  T pivot=a[ix[(n1+n2)/2]];
  do {
      while(a[ix[l]]<pivot) l++;
      while(a[ix[r]]>pivot) r--;
      if(l<=r) {
        int tmp=ix[l];
        ix[l]=ix[r];
        ix[r]=tmp;
        l++;
        r--;
      }
  } while(l<=r);
  if(n1<r) qsix(n1,r,a,ix);
  if(l<n2) qsix(l,n2,a,ix);
  return;
}

template<class T1,class T2>
void qs2(int n1,int n2,T1 *a,T2 *b)
{
  int l=n1;
  int r=n2;
  T1 pivot=a[(n1+n2)/2];
  do {
      while(a[l]<pivot) l++;
      while(a[r]>pivot) r--;
      if(l<=r) {
        T1 tmp1=a[l];
        a[l]=a[r];
        a[r]=tmp1;
        T2 tmp2=b[l];
        b[l]=b[r];
        b[r]=tmp2;
        l++;
        r--;
      }
  } while(l<=r);
  if(n1<r) qs2(n1,r,a,b);
  if(l<n2) qs2(l,n2,a,b);
  return;
}

const int N = 10;

int main()
{
    srand(time(NULL));
    int ia[N];
    string sa[N];
    char tmp[2];
    tmp[1] = '\0';
    for(int i=0;i<N;i++)
    {
        ia[i] = rand();
        tmp[0] = 'A' + i;
        sa[i] = tmp;
    }
    cout << "Usorteret:" << endl;
    for(int i=0;i<N;i++)
    {
        cout << ia[i] << " " << sa[i] << endl;
    }
    int ix[N];
    for(int i=0;i<N;i++) ix[i]=i;
    qsix<int>(0,N-1,ia,ix);
    cout << "Sorteret med index:" << endl;
    for(int i=0;i<N;i++)
    {
        cout << ia[ix[i]] << " " << sa[ix[i]] << endl;
    }
    qs2<int,string>(0,N-1,ia,sa);
    cout << "Sorteret med 2 arrays:" << endl;
    for(int i=0;i<N;i++)
    {
        cout << ia[i] << " " << sa[i] << endl;
    }
    return 0;
}
Avatar billede bertelbrander Novice
23. oktober 2004 - 23:54 #9
En glimrende løsning, man kunne overveje at bruge swap:
http://www.sgi.com/tech/stl/swap.html

Spørgsmålet er måske om det ikke var bedre at have de to arrays som ét array, det kommer naturligvis an på opgaven.
Avatar billede arne_v Ekspert
23. oktober 2004 - 23:59 #10
Normalt vil man forvente at OOA&D vil føre til et array af objekter med 2 felter
fremfor 2 arrays.

Men man kan sagtens forestille sig situationer hvor 2 arrays er givet, fordi
noget eksisterende kode leverer det ene array eller forventer det ene array.
Avatar billede bertelbrander Novice
28. oktober 2004 - 01:06 #11
En noget anderledes løsning (med lidt hjælp fra en kollega):
Ar1 er Key, Ar2 Item.

#include <vector>
#include <algorithm>
#include <iostream>

class SortClass
{
public:
  SortClass(int *aArr) : Arr(aArr)
  { }
  bool operator () (const int &lhs, const int &rhs)
  {
      return Arr[lhs] < Arr[rhs];
  }
  int *Arr;
};

int main()
{
  int Ar1[8] =  {    6,      2,    7,      9,      11,      1,      66,    5};
  char *Ar2[8] = {"Hans", "Grete", "Ole", "Peter", "Niels", "Keld", "Hanne", "Lars"};

  int Temp[8];
  int i;
  for(i = 0; i < 8; i++)
    Temp[i] = i;

  SortClass Sort(Ar1);

  std::sort(Temp, Temp + 8, Sort);
  std::sort(Ar1, Ar1 + 8);

  for(i = 0; i < 8; i++)
  {
      if(i < Temp[i])
      {
        std::swap(Ar2[i], Ar2[Temp[i]]);
        *std::find(Temp, Temp + 8, i) = Temp[i];
      }
  }
  for(i = 0; i < 8; i++)
      std::cout << Ar1[i] << " " << Ar2[i] << std::endl;

  return 0;
}
Avatar billede arne_v Ekspert
28. oktober 2004 - 20:25 #12
Faktisk er det min qsix lavet med std::sort.

Ses nemmere i denne her variant:

#include <vector>
#include <algorithm>
#include <iostream>

class SortClass
{
public:
  SortClass(int *aArr) : Arr(aArr)
  { }
  bool operator () (const int &lhs, const int &rhs)
  {
      return Arr[lhs] < Arr[rhs];
  }
  int *Arr;
};

int main()
{
  int Ar1[8] =  {    6,      2,    7,      9,      11,      1,      66,    5};
  char *Ar2[8] = {"Hans", "Grete", "Ole", "Peter", "Niels", "Keld", "Hanne", "Lars"};

  int Temp[8];
  int i;
  for(i = 0; i < 8; i++)
    Temp[i] = i;

  SortClass Sort(Ar1);

  std::sort(Temp, Temp + 8, Sort);

  for(i = 0; i < 8; i++)
      std::cout << Ar1[Temp[i]] << " " << Ar2[Temp[i]] << std::endl;

  return 0;
}
Avatar billede bertelbrander Novice
28. oktober 2004 - 20:36 #13
En anden model, hvor man slipper for at kalde find for hver element der skal flyttes.
Den er måske optimal hvis listen er meget usorteret og elementerne i listen er små.

#include <vector>
#include <algorithm>
#include <iostream>

class SortClass
{
public:
  SortClass(int *aArr) : Arr(aArr)
  { }
  bool operator () (const int &lhs, const int &rhs)
  {
      return Arr[lhs] < Arr[rhs];
  }
  int *Arr;
};

int main()
{
  int Ar1[8] =  {    6,      2,    7,      9,      11,      1,      66,    5};
  char *Ar2[8] = {"Hans", "Grete", "Ole", "Peter", "Niels", "Keld", "Hanne", "Lars"};

  int Temp[8];
  int i;
  for(i = 0; i < 8; i++)
    Temp[i] = i;

  SortClass Sort(Ar1);

  std::sort(Temp, Temp + 8, Sort);
  std::sort(Ar1, Ar1 + 8);

  char *Ar2Temp[8];
  for(i = 0; i < 8; i++)
      Ar2Temp[i] = Ar2[Temp[i]];

  for(i = 0; i < 8; i++)
      Ar2[i] = Ar2Temp[i];

  for(i = 0; i < 8; i++)
      std::cout << Ar1[i] << " " << Ar2[i] << std::endl;

  return 0;
}
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Kurser inden for grundlæggende programmering

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester