Double sorting integers

Dear Rooters

I know that this is not directly related to root, but:
Does root provide an easy way to sort for two columns of a table?

Here is an example:
Unsorted table:
3 4
0 2
3 5
0 3
1 0
0 1
1 2
1 1
3 7

Sorted table:
0 1
0 2
0 3
1 0
1 1
1 2
3 4
3 5
3 7

Thank you in advance.

Best regards
Christian

Hi Christian,

make an array of Long64_t words (one Long64_t for each pair of integers) and sort the Long64_t* array. See example in TTreeIndex constructor.

Rene

Dear Rene

Wow, this reply was really fast :slight_smile:
Thank you, this is what I was looking for.

Best regards
Christian

[quote=“cstrato”]Dear Rene

Wow, this reply was really fast :slight_smile:
Thank you, this is what I was looking for.

Best regards
Christian[/quote]

You do not need any hacks with Long64_t, use container (array) of std::pair<int_int> + std::sort (replace _ with , - there are problems with this forum and formatting) instead.

[quote=“cstrato”]Does root provide an easy way to sort for two columns of a table? [/quote]What about root.cern.ch/root/htmldoc/TTable … escription

Dear Rooters

Thank you for your suggestions, currently I have adopted the following code:

void DoubleSort(const char *infile, const char *sep = "\t")
{
   ifstream input;
   input.open(infile, ios::in);
   if (!input.good()) {
      cerr << "Error: File does not exist: " << infile << endl;
      input.close();
      return;
   }//if

   char nextline[512];

   Int_t fN = 9;
   Int_t *x = new Int_t[fN];
   Int_t *y = new Int_t[fN];

   Long64_t *w      = new Long64_t[fN];
//?   Long64_t *fIndex = new Long64_t[fN];
   Int_t    *fIndex = new Int_t[fN];

   Int_t idx = 0;
   while (input.good()) {
      input.getline(nextline, kBufSize, '\n');
      if (input.eof()) break;

      x[idx] = atoi(strtok(&nextline[0], sep));
      y[idx] = atoi(strtok(0, sep));

      Long64_t majorv = (Long64_t)x[idx];
      Long64_t minorv = (Long64_t)y[idx];
      w[idx]  = majorv << 31;
      w[idx] += minorv;
cout << "x = " << majorv <<  "   y = " << minorv <<  "   w[i] = " << w[idx] << endl;
      idx++;
   }//while

   TMath::Sort(fN, w, fIndex, 0);

   for (Int_t i=0; i<fN; i++) {
      cout << "x = " << x[fIndex[i]] <<  "  y = " << y[fIndex[i]] << "   fIndex[i] = " << fIndex[i] << endl;
   }

   delete [] fIndex;
   delete [] w;
   delete [] y;
   delete [] x;

   input.close();
}//DoubleSort

It is also attached as macro together with a sample input table.
Sorrowy, CINT cannot handle it, so you have to compile it with ACLiC.

I am wondering whether code using stl methods pair and sort would be as easy.
Currently, I do not see how TTableSorter would be able to do double sorting.

Best regards
Christian
table4test.txt (36 Bytes)
DoubleSort.C (1.63 KB)

[quote]Dear Rooters
I am wondering whether code using stl methods pair and sort would be as easy.
Christian[/quote]

#include <algorithm>
#include <utility>

int main()
{
    typedef std::pair <int_int> p_t;
    //pairs of integers from you original question
    p_t arr[] = {p_t(3,4), p_t(0,2), p_t(3,5), p_t(0,3), p_t(1,0), p_t(0,1), p_t(1,2), p_t(1,1), p_t(3,7)}; 
    std::sort(arr, arr + sizeof arr / sizeof(p_t));
}

Replace int_int with int, int

Hi,

Thank you for this explanation.
The code corresponding to my first code is:

void DoubleSortPair(const char *infile, const char *sep = "\t")
{
   ifstream input;
   input.open(infile, ios::in);
   if (!input.good()) {
      cerr << "Error: File does not exist: " << infile << endl;
      input.close();
      return;
   }//if

   char nextline[512];

   Int_t fN = 9;

   typedef std::pair <int> p_t;
   p_t arr[fN];

   Int_t idx = 0;
   while (input.good()) {
      input.getline(nextline, kBufSize, '\n');
      if (input.eof()) break;

      arr[idx].first  = atoi(strtok(&nextline[0], sep));
      arr[idx].second = atoi(strtok(0, sep));

      idx++;
   }//while

   std::sort(arr, arr + sizeof arr / sizeof(p_t));

   for (Int_t i=0; i<fN; i++) {
      cout << "arr = <" << arr[i].first << ", " << arr[i].second << ">" << endl;
   }

   input.close();
}//DoubleSortPair

Best regards
Christian

[quote]Hi,

{
 
   Int_t fN = 9;
   p_t arr[fN];//<----------------

}//DoubleSortPair

Best regards
Christian[/quote]

This is incorrect C++ construct. fN must be an integral constant expression, for example

const Int_t fN = 9;
p_t arr[fN];
  1. Why does it compile w/o problems?
  2. fN cannot be a constant, since I do not know it in advance.

Is it possible to do “p_t *arr = new p_t[fN]” and “arr[idx]->first”?

Best regards
Christian

[quote]1. Why does it compile w/o problems?
2. fN cannot be a constant, since I do not know it in advance.

Is it possible to do “p_t *arr = new p_t[fN]” and “arr[idx]->first”?

Best regards
Christian[/quote]

  1. It’s a wrong question :slight_smile: You should specify, which compiler (Ok, I guess, it’s g++). In C99 (not in C89) you can do such things:
void fun(int j)
{
   int i = 10;
   int arr[i];
   int arr[j];
}

g++ supports variable-length arrays (C99). So, you have a mixture of C and C++ code, correct C++ compiler cannot compile it (it’s an ill-formed C++ program), C compiler cannot compile it (it’s not a C program), g++ can. :slight_smile:
For example, MSVC 8’ compiler:

main.cpp(4) : error C2057: expected constant expression

Or the most standard compiler comeau

"ComeauTest.c", line 4: error: expression must have a constant value
     int arr[i];

g++ -pedantic :

main.cpp:4: warning: ISO C++ forbids variable-size array `arr'
  1. Use std::vector

Yes, it’s possible to create dynamic array of pairs (and use indicies and array subscript). But… you 'd better use std::vector :slight_smile: Good modern C++ program should avoid where possible raw pointers, there are a lot of good smart-pointers, std::auto_ptr (very specific), there is std::vector, std::valarray etc.
C++ is a language, which supports exception handling. So, to avoid many problems and reduce complexity of code, C++ programmer must use RAII idiom.

Thank you,

However, instead of std::vector I would prefer to use the ROOT class TArray.
Most stl classes have ROOT equivalents, and I prefer to use these, but this
is another story :slight_smile:

Since ROOT does not use exception classes, I had decided not to use them either.

Best regards
Christian

[quote]Thank you,
However, instead of std::vector I would prefer to use the ROOT class TArray.

Most stl classes have ROOT equivalents, and I prefer to use these, but this
is another story :slight_smile:
[/quote]

IMHO if ROOT’s classes have something, std::containers do not - yes, you do not have choice. But if not - you’d better prefer standard classes.

Thats not true. If ROOT uses C++ standard linrary (I quess, it does :slight_smile:) )

  • it already uses exception handling.

new int[10] can throw. typeid can throw. dynamic_cast can throw. Standard containers can throw. etc.

This is ok, however, I prefer to use the ROOT classes whenever there are any.
This is one of the great things of real frameworks like MacApp and ROOT:
They offer you all classes that you need w/o leaving the framework!

BTW, there are no “standard classes” in C++! In contrast to Java, C++ was
designed as language only!

If you look at the ROOT source code then you will see, that ROOT has no
exception classes and ROOT code does not throw exceptions (besides the
standard execeptions mentioned by you).

Best regards
Christian

IMHO.

This makes your program less-portable, and makes you vendor-dependent.
You are happy with your framework and do not see better alternative solutions (for example, if I need GUI, but I do not need any ROOT specific - I will use Qt).
The “real framework like MapApp” is not officially supported and developed more. And if you have a lot of code, which was MacApp-oriented == you have a pile of officially obsolete code.
Yes, I know, ROOT is not MacApp, it’s actively developed - I only want to say: the part of a program, which can be framework independant, MUST be framework independent. So, you can extract the heart of your programm very simply, without re-writing (re-debugging).

BTW, there are no "standard classes" in C++! In contrast to Java, C++ was
designed as language only!

Completely wrong statement. C++ standard library - is a set of standard C++ classes (and non-member functions). std::vector/list/map/set etc. - they are all standard classes. Notion of “standard class” is not limited by GUI, or socket, or file.
The C++ standard library is a very powerful tool (thanks to genius Alex Stepanov and Co). It makes C++ a really good worthwhile modern programming language. Without it, without templates/exceptions etc. you are back to 90s, you only have a language subset - but I guess, you are not an embedded systems programmer?

In your code:
do you use keyword new?
do you use new(std::nothrow) form?

If your answers are : 1. yes 2. no - your code can throw. I did not want to say “USE EXCEPTIONS!!!” in my previous post, I want to say “code should be exception safe, if it’s possible”. (BTW TArray or TFile or TH1F etc. stack objects examples of RAII).

I think, I should stop here :slight_smile: Excuse me for this off-topic.

Regarding stl and templates a agree with:
root.cern.ch/root/roottalk/roottalk06/1015.html
root.cern.ch/root/roottalk/roottalk06/1016.html

BTW, one of the reasons for Rene to develop ROOT was to ensure that the
framework will still be available in 20-30 years.
As you mentioned this is no longer the case with MacApp and may not be
the case with QT (although both MacApp and QT have the advantage that
the source code is available, which would not be the case for commercial
frameworks)!

So, I agree with you, we should stop here.

Best regards
Christian

[quote=“cstrato”]Currently, I do not see how TTableSorter would be able to do double sorting.[/quote]One can define this via vclass ctor
root.cern.ch/root/htmldoc/TTable … ableSorter

[code]TTableSorter(const TTable &table, SEARCHMETHOD search, COMPAREMETHOD compare, Int_t firstRow,Int_t numberRows)

TTableSorter ctor sorts the input table according the function “search”

- search     - the function to compare the "key" and the table rows during sorting
               typedef Int_t (*SEARCHMETHOD) (const void *, const void **);

- compare    - the function to compare two table rows during searching
               typedef Int_t (*COMPAREMETHOD)(const void **, const void **);

- firstRow   - the first table row to sort from (=0 by default)
- numberRows - the number of the table rows to sort (=0 by default)
               = 0 means sort all rows from the "firstRow" by the end of table

TTableSorter(const TTable *table, SEARCHMETHOD search, COMPAREMETHOD compare, Int_t firstRow,Int_t numberRows)

TTableSorter ctor sorts the input table according the function “search”

- search     - the function to compare the "key" and the table rows during sorting
               typedef Int_t (*SEARCHMETHOD) (const void *, const void **);

- compare    - the function to compare two table rows during searching
               typedef Int_t (*COMPAREMETHOD)(const void **, const void **);

- firstRow   - the first table row to sort from (=0 by default)
- numberRows - the number of the table rows to sort (=0 by default)
               = 0 means sort all rows from the "firstRow" by the end of table

[/code]The UNIX man page for “qsort” and “bsearch” subroutines may ngiev some extra information too.

Dear Valeri

Thank you, however, I do not have time to figure that out.
Furthermore, it seems that I have to store my data in TTable in order to use TTableSorter.

Best regards
Christian

[quote=“cstrato”]Thank you, however, I do not have time to figure that out.[/quote]Yes, people always are busy writing and debugging there own version of the code for weeks because they have no 5 min to read the man page :frowning: [quote=“cstrato”] Furthermore, it seems that I have to store my data in TTable in order to use TTableSorter.[/quote]I do not know what you meant speaking “store”. TTable class is a wrapper around of the regular C array of the regular C structure. The TTable object can (if one wants) own that array too (i.e. the TTable object can create /delete array optionally). Check the various TTable ctors to see that (yes, it might have taken you another 3 min :slight_smile: ). TTable can “adopt” the external array via Adopt method too.

One more commnet about TTableSorter . Pay your attention that one can create unlimited number of the different TTableSorter’s around of one and the same array of C-structure. TTableSorter doesn’t change the array itself. It provides the iterator for C-array using the user provided “search/compare” methods.