Getting the closest value in an array

Hi,
I'm new at programming, so I'm grateful for any clues/pointers. I have a list of dates and corresponding prices of the S&P 500 Index for 1 calendar year. However, I want to write a function where if a user inputs two dates, it will take the last trading date. So, for example:
11/2/2007 -- Friday
11/5/2007 -- Monday.

If the input is 11/4/2007 (Sunday), I would like to take Friday's Date. I have part of the code written here. I already have a class Date written.. but here is the main part. However, I'm having trouble writing the part that is supposed to recognize if the start_date does not equal a corresponding element in the date array. Am I starting out wrong? Could I use "goto" command? Thanks for your help!!!

--------------------------------------------------------------------

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <iostream>;
using namespace std;

int main()
{
const int max = 250;
  for (int i = 0; i <= max; i++)
      { 
        if (start_date ==  array[i].date) // if the input date equals to a
           {
             start_date_place = i;
            }
        else if (start_date != array[i].date)
            { // WHAT DO I DO HERE?
            }
       }
 return 0;
} 






Firstly, you do not need a ; at the end of your #includes.

Second, you should have for (int i = 0; i < max; i++). < will mean 250 iterations, <= will mean 251 iterations (Edit: Fixed)

Next, Do you even need an else-if statement? If the start date matches then set it to i and break.
Last edited on
You bring up good points. Yes, I realized my mistake afterwards. There is no ";" necessary after the #include.
After testing, I do want the <= instead of "<". However, my question is not answered. In the event that the inputted date is not contained in the list, how do I get the last trading date? That is, after the break, how can I write the condition so it takes the last date?

Thanks again!
If you already know the last trading date, make that the default value for start_date_place. Then it's over-written if a match occurs.
<=max will cause max+1 iterations. <max will cause max iterations.

The simplest way to do what you want is to simply subtract one from the date until it matches the condition you need.
Hi Helios,
I dont' think I'm doing it right. Can you help? I just don't think I have it down.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <iostream>
using namespace std;

int main()
{
const int max = 250;
  for (int i = 0; i <max; i++)
      { 
        if (start_date ==  array[i].date) // if the input date equals to a
           {
             start_date_place = i;
            }
        else if (start_date != array[i].date)
            { 
             do (start_date == array[i].date;
                   --i;
                  break;
            }
       }
 return 0;
} 
I think this is what you need to do:
1. Scan the array and look for the date that is closest to the one you have. If at one point you find an exact match, break the loop and set a flag that indicates the date was found.
2. If the flag is not set, use the closest date you already have.
OK. Conceptually, I understand. Could i use the goto command here? What commands could I use?
No, goto is not necessary.
Ok. Then. Can you give me clues as to what commands? I'm not asking you to write it for me. I'm at an absolute loss, which is I posted on this forum for your help.

Thank you.
You'll need one for, one break (avoidable), and two ifs.
Off you go.
Hi, I've been trying out various things, but I keep on getting stackdump errors! GRR!!! Other ways, it's has produced 0 output. Can you tell me what I'm doing wrong?

Thanks again!


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <iostream>
using namespace std;

int main()
{
const int max = 250;
  for (int i = 0; i <max; i++)
      { 
        if (start_date ==  array[i].date) // if the input date equals to a
           {
             start_date_place = i;
            }
        else if (start_date != array[i].date)
            { 
             start_date == array[i-1].date;
             break;
             start_date_place = i-1;
             }
       }
 return 0;
} 
Last edited on
For one, you're using the same code as before.
Actually, it is not. If you're not going to provide any useful and constructive help and advice, I'd appreciate it if you would not write snippy one line comments. If you are not going to provide any constructive help or examples, it is frankly difficult to understand why you are spending so much time on this board to respond to 700 postings on a public forum, which is used to help others learn C++. You're not being an effective teacher in this situation.

If you are so inclined to help, thank you then for providing more useful feedback and actually pointing out what I'm doing wrong.

When I add cout to test it, the following code below produces an output of all 0s and then goes through the entire list of prices.

Please advise.

Thank you to anyone who can provide helpful feedback!

----------------------------------------------------------------------------------------------

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
#include <iostream>
 
using namespace std;
 
int main()
{
const int max = 250;
int j = 0;

for (int i = 0; i <max; i++) 
    {
       if (start_date != array[i].date)
	{	     
	  break;
	  j++;
	  start_date == array[i-j].date;
	  start_date_place = (i-j);
         }

      if (start_date == array[i].date) 
	{
	  start_date_place = i;
	}
    }

return 0;
}
It wasn't? Well, it certainly looked an awful lot like the one from before.

PROTIPS:
1. Any code in the same block after a break statement is ignored.
2. Your conditions seem to be inverted when compared to the contents of their blocks.
3. Don't if (a){} if (!a){}. Instead if (a){}else{}
Here is a quick tip what I would do for your scenario.

Assuming the dates are ordered in the array, I would start looking for a match or closest and stop if not.
Meaning, if the dates are 1/1/2008, 1/2/2008, 1/4/2008, 1/5/2008, 1/8/2008 and I am looking for Jan 6th, which 1/6/2008 then
it should either give you the match 1/6 (which is not available in this case)or closest (available). The result would be 1/5/2008 that is the closest/earliest date to the desired.

1
2
3
for ( i = 0; i < max && start_date <= array[i]; i++); 

cout << "this is the closest date " < array[i-1] << endl;



The single line loop keeps checking until i reaches max or start_date is no longer <= array[i]. meaning, it stops when start_date is NOT <= array[i].

So take the last checked one, that is array[i-1], as array[i] is not <= the start date and stopped the loop.

That simple. Hope you understand it now. Good luck :)



Last edited on
Hi. I have a question. Because I have the start_date and end_date as strings, would your code above be able to sort through strings? The way I have my date is as a string: "mm/dd/yyyy". If I apply your logic above, I keep on getting an error message if it's in the Part 2 or Part 4 cases! I just can't seem to make it work!! Where am I lost? Please advise! Thank you so much for any help!

P.S. - the dates are ordered in the array

Here is an excerpt of my program:

-----------------------------------------------------------
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
78
#include <iostream>
#include <iomanip>
#include <fstream>
#include <string>
#include <stdlib.h>
#include <stdio.h>

using namespace std;

using std::cout;
using std::endl;

const int MAX_NUM=2500;  

struct MyStruct
{
  int month, day, yr;
  float price; 
  string date; // the string date
  long index;  
}; 

MyStruct d[MAX_NUM];

void PriceList (string StartDate, string EndDate, float price_array[])
{
   
  StartDate = "12/18/2007";
  EndDate = "12/31/2007";

  int StartEndPt = 0;  // location in the array
  int EndDatePt= 0;

   // PART 1: When the beginning date is a trading date (in the array)
   for (int j = 0; j <MAX_NUM; j++)
    {
      if (StartDate == d[j].date)
	{
	  StartDatePt = j;
	  //cout << StartDatePt << endl;
	}
    }

  // PART 2: When the beginning date is a non-trading date (not in the array)
      for (int x = 0; x < MAX_NUM && StartDate >= d[x].dat; x++)
    {
      StartDatePt = d[i-1].date;
    }



    // PART 3: When the end date is a trading (in the array)
   for (int k = 0; k <MAX_NUM; k++)
    {
      if (EndDate == d[k].date)
	{
	  EndDatePt = k;
	  //cout << EndDatePt << endl;
	}
    }

    // PART 4:When the end date is a non-trading date (not in the array)

  for (int i = 0; i < MAX_NUM && EndDate <= d[i].dat; i++)
    {
      EndDatePt = d[i-1].date;
     }

   // print out the prices between the specified dates
  for (int x = StartDatePt; x <= EndDatePt; x++)
    {
      price_array[x] = d[x].price;
 
      cout << "The prices between " << StartDate << " and " << EndDate << " :" <<  price_array[x] << endl; 
 
    }
}
Last edited on
The best way to keep the values sorted/ordered is to store in yyyymmdd or yyyy/mm/dd format.
If the values are sorted in the above format and yes, my logic should work.
It is very simple logic.

And in your code, you are mixing up the values StartDataPt in part-1 and part-2, as you are storing the location/position in first place and immediately in next loop you are replacing it with a date. And i-1 in part-2 is unknow as you are using "x" for the loop.

I am not even sure why are you giving two loops for one. If you want to locate a start date closest to the given, try similar to the end date I suggested. Meaning, replace the part-1 and part-2 with below:

(assuming you are looking for closest suitable starting date to the given)
1
2
3
4
5
6
7
8
9
10
      for (int x = 0; x < MAX_NUM && StartDate >= d[x].dat; x++);  // single-line loop
   
      StartDatePt = d[x-1].date; 

    
   for (int i = 0; i < MAX_NUM && EndDate <= d[i].dat; i++); // single-line
    
   EndDatePt = d[i-1].date;
     


Remove all part-1, 2, 3, and 4 and place the above code and just run it with your print loop.
Thats all.

If your date structure is not sorted, post it here and I would like to see. If possible, following the above suggested format to store the dates in. It would be easier to sort them out.

If your data is not sorted/formatted in the way I suggested, there is a quick work-around.
Change the date string format on fly and compare it as desired.
For example, assuming your date members of the structure store the values those are same of date string, create a temporary variable to combine those three date values using a stringstream like:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
    #include <sstream>   // include at top
   
     //inside the function 
         ostringstream ostr;
      
         StartDate = "2007/12/18";   // store in yyyy/mm/dd format
         EndDate = "2007/12/31";

         
         //in the loop
         {
            ostr << d[i].yr << "/"; 
            if (d[i].month < 10) ostr << "0";
            ostr << d[i].month; << "/"
            if (d[i].day < 10) ostr << "0";
            ostr << d[i].day;

            string dateString = ostr.str();  // extract the date from formated stream
        
            //now check here the dateString against StartDate or EndDate  
         
         }


Though I would not recommend strstream as it is predecated, you could use ostrstream for such concatenation, if your compiler supports. Please note strstream works with char * rather than string objects and some compilers do not support it any more.

If your date member struct is already stores the dates in yyyy/mm/dd format, then you would not need strstream proc at all. Just follow the other steps suggested.

Check it out. Good luck :)



EDIT: I just cut and pasted your code and modified it to be as suggested above;

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
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
#include <iostream>
#include <iomanip>
#include <fstream>
#include <sstream>  // add this new one
#include <string>
//#include <stdlib.h>   // may not be needed unless you used any c func
//#include <stdio.h>    // ditto

using namespace std;

//using std::cout;     // above namespace works for the same purpose
//using std::endl;

const int MAX_NUM=2500;  

struct MyStruct
{
  int month, day, yr;
  float price; 
  string date; // the string date
  long index;  
}; 

MyStruct d[MAX_NUM];

void PriceList (string StartDate, string EndDate, float price_array[])
{
   
     StartDate = "2007/12/18";  // change the format to be yyyy/mm/dd
     EndDate = "2007/12/31";

     int StartEndPt = 0;  // location in the array
     int EndDatePt= 0;


     ostringstream ostr;
     string dateString;

      for (int i = 0; i < MAX_NUM; i++)
     {
        ostr.clear();
        ostr << d[i].yr << "/"; 
   
        if (d[i].month < 10) ostr << "0";
        ostr << d[i].month; << "/"
    
        if (d[i].day < 10) ostr << "0";
        ostr << d[i].day;

         dateString = ostr.str();  // extract the date from formated stream
        
         //now check here the dateString against StartDate or EndDate  
         
         if (StartDate >= dateString) // search no further if StartDate is found be lower than the date string
            continue;
         else 
            break;
    }

     //now note the position where it stopped at last
      StartDatePt = i-1;

    // now do the similar for EndDate too

    for (int i = 0; i < MAX_NUM; i++)
    {
        ostr.clear();
        ostr << d[i].yr << "/"; 
   
        if (d[i].month < 10) ostr << "0";
        ostr << d[i].month; << "/"
    
        if (d[i].day < 10) ostr << "0";
        ostr << d[i].day;

        dateString = ostr.str();  // extract the date from formated stream
        
         //now check here the dateString against StartDate or EndDate  
         
         if (EndDate <= dateString) // search no further if EndDate found to be greater 
            continue;
         else 
            break;
    }

    EndDatePt = i-1;

    // print out the prices between the specified dates
    for (int x = StartDatePt; x <= EndDatePt; x++)
    {
      price_array[x] = d[x].price;
 
      cout << "The prices between " << StartDate << " and " << EndDate << " :" <<  price_array[x] << endl; 
 
     }
}
Last edited on
Hi there - thanks so much for the suggestions!

The date is sorted ascending order. I'm trying to load up text files that contain prices of American date format: mm/dd/yyyy. The input at "StartDate" is to test out my code to see if it works.

Couple of changes:

I'm not taking any closest date, but the ones that fall between those dates. That is, if I were to take from 2/15/2007 to 3/19/2007, I'd want the prices between those 2/17 (monday) to 3/17 (friday).

2/14/2007 - Friday
2/15/2007 - Saturday
2/16/2007 - Sunday
2/17/2007 - Monday

...

3/17/2007 - Friday
3/18/2007 - Saturday
3/19/2007 - Sunday

In addition, when I do it the first way, I get a bunch of weird errors on Cygwin, the free linux compiler.


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

include <iostream>
#include <iomanip>
#include <fstream>
#include <sstream>  // add this new one
#include <string>
//#include <stdlib.h>   // may not be needed unless you used any c func
//#include <stdio.h>    // ditto

using namespace std;

//using std::cout;    
//using std::endl;

const int MAX_NUM=2500;  

struct MyStruct
{
  int month, day, yr;
  float price; 
  string date; // the string date
  long index;  
}; 

MyStruct d[MAX_NUM];


void PriceList(string StartDate, string EndDate, float price_array[])
{

  int StartDatePt =0;
  int EndDatePt =0;
  
  StartDate = "12/20/2004";
  EndDate = "12/31/2004";
 
  for (int i = 0; i < MAX_NUM && StartDate >= e[i].date; i++);
  StartDatePt = e[i+1].date;

  for (int j = 0; j < MAX_NUM && EndDate <= e[j].dat; j++);
  EndDatePt = e[i-1].date
 

  for (int m = StartDatePt; m <= EndDatePt; m++)
    {
      price_array[m] = e[m].pr;
 
      cout << "The prices between " << StartDate << " and " <<  EndDate << " :" <<
	  price_array[m] << endl; 
 
	  } 
}



I get various errors like" obsolete binding " and "scoping".

Thanks for your help.
Last edited on
It would be easier if you could you post the errors here.

And about dates, as mentioned earlier, it would be easier if there are in yyyymmdd format and the suggested work-around is for a change to be applied on fly in the loop.

And I notice that, you assigned e[i-1].date for EndDatePt where you used, in fact, the iterator j. It should be e[j-1].date and a semicolon is missing in the line.

With the format you noted would not work as desired in StartDate >= e[i].date or EndDate <= e[j].date

Check the date variable name, as it appears as .dat in second loop and .date in first loop.

The code I suggested is I typed directly here so I would not know any typos or compiler errors.

Check it out. Good luck :)
Topic archived. No new replies allowed.