sorting a 2D-array

Hey guys,

i have a challenging problem. I`m importing a value which has the date of an entire year (12 months) into an 2D-Array with 31 rows and 12 columns. The problem is that some years is considered as leap year and some are not ( for ex. 28th of feb and some years has 29th of feb.) Also, some months has 30 days , some months has 31 days. How can you save the values of the year into the array and sort them in a way that I will be able to know the date from the array parameters.

dates can be converted to a sortable value, is one way, using the c++ date and time features.

you can also do it yourself by cooking up a string or an integer
eg
20170228 is less than 20170314 //feb 28 is less than march 14, correct integer comparison

you can do that with year * 10000 + month * 100 + day

what else you do depends exactly on what the user needs. If the user still needs a year column and a day column etc, leave that in place and add this as a dummy column used only for sorting and keep it hidden from the user.

the trick to doing these sorts of things (keep this in mind later for file names that you might like to sort, or just about anything else you ever want to sort) is the right to left ordering of the most significant part (year, in this case) followed by the next most significant ... etc. For time, for example, its hours min sec fractional sec ... and you can mix and match them, such as filename1datetime all concat will sort in a directory listing by name then by date then by time.

Last edited on
Thank you so much for replying. But the date is written as follow 28.02.2017. is it possible to convert it to other format?

Also, I don't get your solution. This condition is going to be true no matter if the month is complete or not ( if it's 28 or 29 days) , right?
yes, you can convert it to whatever format you like. Not always converted directly (I forget what formats the c++ date conversions can handle, I get mixed up with sql and other stuff, and I rarely do date/time in c++ so I have to look it up every time), but with only a little bit of code if not.

the number of days does not matter. Converting to an integer it will sort first by year (2016 is before 2017 numerically, and 1923 is before 2016, etc .. works until you get to BC at least). Then it sorts by the month, so 201601 (January comes before 201612 (December). Then it sorts by the day, so 20160101 (new years) comes before 20160115 (1-15-2016)

it will automatically handle leap years (feb 29th is before march 1st numerically).

Its just a slick way to put the date into a numerical format such that they are in the correct order. So long as you do NOT somehow drop leading zeros on the month and day (you need them so that 20160101 does not become 201611).
Last edited on
Since you haven't really shown an code I have a couple of questions.

First why are you using arrays instead of std::vector? It is quite easy to have a vector of vector that has different sized inner vectors.

Second have you considered using a structure to hold your data, this structure could hold the date along with any other associated data.

@jonnin: Oh I see your point now. I got it arranged like that already. But I want to arrange in a way that each COLUMN has the values of ONE month only. Basically, my array is 2d with 31 rows and 12 columns.

Some months has 30 days, some 31 days. How could I over come this problem and tell the code to jump the next month if there are no more days left for this month.

For ex. if I'm considering feb. , the program should read till 28 or 29th of Feb. only and then make empty rows ( 3 or 2 rows) and then fill the row with the march.

For me, it seems impossible :(

@jlb: it's challenging and I have to use arrays.
@jlb: it's challenging and I have to use arrays.


Maybe, but @jlb's suggestion of vectors and structs would make your task straightforward (and the storage much more efficient). A vector is just an array on steroids.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
#include <iostream>       
#include <iomanip>
#include <fstream>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;

//===============================================

void fromDateString( string text, int &day, int &month, int &year )            // Change dd.mm.yyyy to integers
{
   day   = stoi( text.substr( 0, 2 ) );
   month = stoi( text.substr( 3, 2 ) );
   year  = stoi( text.substr( 6, 4 ) );
}

//===============================================

struct MyData
{
   int year;
   int month;
   int day;
   double value;             // Change the type etc. as necessary

   MyData( int y, int m, int d, double v ) : year( y ), month( m ), day( d ), value( v ) {}       // Construct from individual values
   MyData( string text, double v ) { fromDateString( text, day, month, year ); value = v; }       // Construct from dd.mm.yyyy value
};

//===============================================

bool lessDate( MyData a, MyData b )              // Comparison of dates
{
   return 10000 * ( a.year - b.year ) + 100 * ( a.month - b.month ) + ( a.day - b.day ) < 0;
}

//===============================================

bool lessValue( MyData a, MyData b )             // Comparison of values
{
   return a.value < b.value;
}

//===============================================

ostream &operator<<( ostream &strm, MyData a )   // Output (insertion) operator for struct MyData
{
   return strm << a.year << setw( 3 ) << a.month << setw( 3 ) << a.day << "   " << a.value;
}

//===============================================

int main()
{
   // Alternative input formats
// vector<MyData> dataset = { { 2010, 12, 31, 5.5 },          // You would probably read from file
//                            { 2012,  4, 20, 6.8 },
//                            { 2015,  1, 15, 3.2 },
//                            { 2011,  5, 10, 9.6 },
//                            { 1998,  1,  1, 7.2 } };
   vector<MyData> dataset = { { "31.12.2010", 5.5 },         
                              { "20.04.2012", 6.8 },
                              { "15.01.2015", 3.2 },
                              { "10.05.2011", 9.6 },
                              { "01.01.1998", 7.2 } };

   cout << "\nSort by date:\n";
   sort( dataset.begin(), dataset.end(), lessDate );
   for ( auto x : dataset ) cout << x << endl;

   cout << "\nSort by value:\n";
   sort( dataset.begin(), dataset.end(), lessValue );
   for ( auto x : dataset ) cout << x << endl;
}

//=============================================== 

Sort by date:
1998  1  1   7.2
2010 12 31   5.5
2011  5 10   9.6
2012  4 20   6.8
2015  1 15   3.2

Sort by value:
2015  1 15   3.2
2010 12 31   5.5
2012  4 20   6.8
1998  1  1   7.2
2011  5 10   9.6
Last edited on
lastchance wrote:
lb's suggestion of vectors and structs would make your task straightforward

But then he will fail his arrays challenge? OP clearly stated he has to use arrays.

arrays have fixed dimensions so you will have to create the array 12x31 to cover all possible days.

Only one date changes in our calendar, FEB-29 may or may not exist.

So, have a function int LastDay(Month, Year) which returns the last day of the given month for the given year. Use this to bounds check your array.

The only alternative is to save some marker value into the array to indicate days are not used, but then you will probably need more than one marker, one to indicate no day and another to indicate no data.

I would go with the function,
1
2
3
4
5
6
7
8
if ( (mm >= 1 && mm <12) && (dd <= LastDayOf(mm,yyyy)) )
{
    DoSomething(myArray[mm][dd]);
}
else
{
     //invalid date!
}
Just watch out for those array bounds!

For ex. if I'm considering feb. , the program should read till 28 or 29th of Feb. only and then make empty rows ( 3 or 2 rows) and then fill the row with the march.

Well since you still haven't posted any code, nor a sample of your input file, we can only guess as to what you are really doing. You need to post some code showing what you're attempting to do along with a small sample input file.

arrays have fixed dimensions so you will have to create the array 12x31 to cover all possible days.

Even if arrays are a must, it is possible to have ragged arrays, probably not advised but it is possible.

How can you save the values of the year into the array and sort them in a way that I will be able to know the date from the array parameters.

IMO, unless absolutely required by the assignment, this is a really bad idea.




Here is a sample of the code I have worked on to input the file:
1
2
3
4
5
6
7
8
9
10
11
12
13
  
string we[31][12]={"100"};
   string we1[31][12]={"100"};
   ifstream inFile;
   inFile.open(x.csv);
   ofstream outFile("x-1.html");     

    for (int i=0;i<12;++i) {
    for (int j=0;j<31;++j){


    }
    }


The input file looks like this: https://i.imgur.com/wAFTk5B.png

I have no idea how to make the program undetstand if the month has ended (whether it's 30-29...etc) then, stop and start a new month or at least don't fill the array. That's why i tried to fill the array with 100 so that I can make an if condition later to exclude any cell which has 100 as a value.

The input file could any year ( leap or not)
None worked out for me. Any hint?
Do you think I should change my input technique to an overload operator>>?
Last edited on
Any hints boys
First of all, @pir4t3x, you are still refusing to say precisely what you are trying to do. So to put some context to it, here are links to your earlier posts:
http://www.cplusplus.com/forum/beginner/225058/#msg1028749
http://www.cplusplus.com/forum/general/224997/#msg1028594
and I have a shrewd suspicion that @roaa is doing the same assignment here:
http://www.cplusplus.com/forum/general/225377/#msg1029809

So, to your code (which won't compile).

Reading between the lines from this thread and the related ones above, you have data in files like duisburg-2017.csv (somewhat different from your code). What you are going to do with that data is still unclear, but I can't see any good reason for writing it to an html file. In that csv file there are a succession of lines like
08.05.2016;20.5

That is,
- a date string in the form dd.mm.yyyy
- a semicolon
- a temperature (expressed as a double)


So, with regards to your code:
(1) The year is contained in the name of the file; it does not need to go in the array in any way.

(2) You wish to work with a single array, of type double[12][31], to hold temperatures. So be it, although I have yet to see a precise statement of the assignment that demands it. The type should be double, not string, as temperature is a floating-point value.

(3) You do not need to read the file with nested do loops over month(i) and day(j). This makes life unnecessarily difficult, because different months have different lengths, and one of them will change with leap years. My experience with Met data is that there are often missing days anyway, due to instrument, datalogger or communications failure. Reading the date string (e.g. "08.05.2016") will tell you month (e.g. 5) and day (e.g. 8). You simply need to read the file until the lines are exhausted; a single while loop will do that.

(4) You can extract month(i) and day(j) from the date string (there is already a routine in this thread to do that). These can be used to assign temperatures at the appropriate indices in the temperature array.

(5) You will have to be careful with array bounds: if you have double[12][31] then the array indices will go 0-11 and 0-30; think about whether these correspond to the usual month or day numbers.

(6) Once you have read the latter part of each line into a string, you can extract a double (the temperature) from that string using a stringstream. It is covered (well) in the tutorial on this website. I think you would benefit from reading that tutorial.

(7) Finally, I do not see why the title of this thread is "Sorting a 2D array". Apart from the fact that sorting a multi-dimensional array is pretty undefined, it seems to have little bearing on what you are doing.
Last edited on
Topic archived. No new replies allowed.