0

I have made a form that collects data which is then sent to a database.

Database has 2 tables, one is main and second one is in relation 1-to-many with it.

To make things clear, I will name them: main table is Table1, and child table is ElectricEnergy.

In table ElectricEnergy is stored energy consumption through months and year, so the table has following schema:

ElectricEnergy< #ElectricEnergy_pk, $Table1_pk, January,February, ...,December, Year>

In the form, user can enter data for a specific year. I will try to illustrate this bellow:

Year: 2012

January : 20.5 kW/h

February: 250.32 kW/h

and so on.

Filled table looks like this:

   YEAR | January | February | ... | December | Table1_pk | ElectricEnergy_pk |
   2012 |   20.5  |  250.32  | ... |   300.45 |      1    |     1             |
   2013 |   10.5  |  50.32   | ... |   300    |      1    |     2             |
   2012 |   50.5  |  150.32  | ... |   400.45 |      2    |     3             |

Since the number of years for which consumption can be stored is unknown, I have decided to use vector to store them.

Since vectors can’t contain arrays, and I need an array of 13 ( 12 months + year ), I have decided to store the form data into a vector.

Since data has decimals in it, vector type is double.

A small clarification:

vector<double> DataForSingleYear;
vector< vector<double> > CollectionOfYears.

I can successfully push data into vector DataForSingleYear, and I can successfully push all those years into vector CollectionOfYears.

The problem is that user can enter same year into edit box many times, add different values for monthly consumption, which would create duplicate values.

It would look something like this:

    YEAR | January | February | ... | December | Table1_pk | ElectricEnergy_pk |
    2012 |   20.5  |  250.32  | ... |   300.45 |      1    |     1             | 
    2012 |    2.5  |    50.32 | ... |   300    |      1    |     2(duplicate!) | 
    2013 |   10.5  |    50.32 | ... |   300    |      1    |     3             |
    2012 |   50.5  |  150.32  | ... |   400.45 |      2    |     4             |

My question is:

What is the best solution to check if that value is in the vector ?

I know that question is “broad” one, but I could use at least an idea just to get me started.

NOTE: Year is at the end of the vector, so its iterator position is 12. The order of the data that will be inserted into database is NOT important, there are no sorting requirements whatsoever.

By browsing through SO archive, I have found suggestions for the usage of std::set, but its documentation says that elements can’t be modified when inserted, and that is unacceptable option for me.

On the other hand, std::find looks interesting.

( THIS PART WAS REMOVED WHEN I EDITED THE QUESTION:

, but does not handle last element, and year is at the end of the vector. That can change, and I am willing to do that small adjustment if std::find can help me.

)

The only thing that crossed my mind was to loop through vectors, and see if the value already exists, but I don’t think it is the best solution:

    wchar_t temp[50];  
    GetDlgItemText( hwnd, IDC_EDIT1, temp, 50 );  // get the year 
    double year = _wtof( temp );  // convert it to double, 
                                  // so I can push it to the end of the vector 

    bool exists = false; // indicates if the year is already in the vector

   for( vector< vector <double> >::size_type i = 0;
        i < CollectionOfYears.size(); i++ )

      if( CollectionOfYears[ i ] [  ( vector<double>::size_type ) 12 ]  == year ) 
      {   
        exists = true; 
        break; 
      }

   if( !exists) 
     // store main vector in the database
   else
     MessageBox( ... , L”Error”, ... );

I work on Windows XP, in MS Visual Studio, using C++ and pure Win32.

If additional code is needed, ask, I will post it.

Thank you.

AlwaysLearningNewStuff
  • 2,939
  • 3
  • 31
  • 84
  • 4
    What do you mean `std::find` doesn't handle the last element? And no you can't modify members of `std::set` but you can `erase` and `insert` a new one. – Jonathan Potter Aug 21 '13 at 21:32
  • In the answer below, it is explained to me why my note about std::find is erroneous. Thank you for your remarks Mr.Potter. – AlwaysLearningNewStuff Aug 21 '13 at 22:13
  • @Jonathan Potther, I have a question Mr.Potter, regarding the comparison of doubles: I have read somewhere online, that if you compare two doubles ( say 5,5 and 5,5 ) an error might occur because of default precision. In my question, year is a double, but it will have no decimals, since years are whole numbers. Is there any chance that the precision issue might arise because year will be of type double ? Thank you. Regards. – AlwaysLearningNewStuff Aug 22 '13 at 20:59
  • If they're whole numbers why not use `int` anyway? Otherwise, you could cast to `int` when you do the comparison to make sure, although a `double` should be able to handle small numbers with enough precision that the comparison will be reliable. – Jonathan Potter Aug 22 '13 at 21:02
  • Well, monthly consumption is in decimals, and I need a year as well, so I have decided to store it all in a vector ( 12 monthly consumptions are double + year is int ). Since I get the year from edit control, I can use _wtof_s() to convert it to double. I have checked my code, and it stores the year correctly in the database. However, I was reading an article on floats precision by Bruce Dawson, and I've got scared, so I thought to ask for oppinion to be on the safe side. – AlwaysLearningNewStuff Aug 22 '13 at 21:40
  • There may be some information here for you: http://stackoverflow.com/questions/17333/most-effective-way-for-float-and-double-comparison – Jonathan Potter Aug 22 '13 at 21:54
  • I saw that question, but from various articles/questions I have concluded that problem occurs when there are decimals, I am just not certain if there will be problems for numbers without decimals stored as double. Thanks again Mr.Potter. Regards! – AlwaysLearningNewStuff Aug 22 '13 at 22:00

1 Answers1

2

Using find_if and lambda filter:

auto match = std::find_if(CollectionOfYears.begin(), CollectionOfYears.end(), 
                           [&year](v){ return year == v.last(); })
if (match == CollectionOfYears.end()){ //no value previously

}

This still iterates the whole array. If you need more efficient search you should keep the array sorted and use binary search or std::set.

Note that vector::end() returns iterator to the element after the last element. This is why std::find ignores the last value (because it is already out of bounds!).

  • Your answer about std::find helped me to understand my error. As for your solution, I have never used lambda filter and find_if before, so I have trouble to understand your code. I will need to study it before I can report my results. Thank you for your answer. – AlwaysLearningNewStuff Aug 21 '13 at 22:19
  • I have a question Mr.Keskinen, regarding the comparison of doubles: I have read somewhere online, that if you compare two doubles ( say 5,5 and 5,5 ) an error might occur because of default precision. In my question, year is a double, but it will have no decimals, since years are whole numbers. Is there any chance that the precision issue might arise because year will be of type double ? Thank you. Regards. – AlwaysLearningNewStuff Aug 22 '13 at 20:59