Finding index in an ArrayList - java

I have a CSV file that i stored as an arraylist in Java. Here's the code i ran
public class StockData {
private ArrayList<StockRecord> records;
public StockData() {
records = new ArrayList<StockRecord>();
}
//reads the file from the folder
public void loadPriceData(String filepath) {
try {
Scanner scanner = new Scanner(new FileReader(filepath));
String line;
StockRecord record;
scanner.nextLine();
while (scanner.hasNextLine()) {
line = scanner.nextLine();
String[] results= line.split(",");
double open = Double.parseDouble( results[1]);
double high = Double.parseDouble( results[2]);
double low = Double.parseDouble( results[3]);
double close = Double.parseDouble( results[4]);
double volume = Double.parseDouble( results[5]);
double adjClose = Double.parseDouble( results[6]);
//create the record
record = new StockRecord(results[0], open, high, low, close, volume, adjClose);
records.add(record);
}
scanner.close();
} catch (Exception e) {
System.out.println("Error: " + e.getMessage());
}
}
}
The code works correctly however, i am having trouble with the next part of the project.
Data Example
Date Open High Low Close Volume Adj Close
6/10/2011 128.85 128.93 127.26 127.6 238629400 126.97
6/13/2011 127.89 128.24 127.05 127.7 207599800 127.07
6/14/2011 128.87 129.77 128.82 129.32 160570400 128.68
6/15/2011 128.24 129.3 126.68 127.02 300958000 126.39
6/16/2011 127.06 127.97 126.32 127.3 308032800 126.67
I'm trying to print out the AdjClose price for a date range. say between 6/13/2011 and 06/15/2016. It seems like i would need to find the index of the date first and then print the price record.
How can i do this? I'm not sure where to start. Do i first need to save the date in the its own list/array and use that to find the index?
Thanks

You would need to iterate through the list of StockRecord and compare each record's date to your specified range. If it falls in the range you would print it. This can be optimized if your list is sorted.

To compare first date is preferable to use a data type date
If your array could scouring records and objects of type StockRecord comparing your date field you want to evaluate
for (StockRecord reg : records) {
if(reg.date.after(historyDate) && reg.date.before(futureDate)) {
System.out.println(reg.toString()); // print object
}
}

Your Question is really a duplicate of many others in Stack Overflow.
LocalDate
Your example code does not actually show the date as part of your StockRecord class. But it should be a member of type LocalDate. Search Stack Overflow for countless posts on how to parse your input string into a LocalDate.
Comparator
Define a Comparator for your class, to extract the LocalDate for comparisons. The LocalDate class itself implements the compareTo method, as well as isBefore, isAfter, and isEqual.
Benefit of sorting
If you will be doing this query often, then it makes sense to sort the StockRecord objects into a List. Then you can be smart about searching, again discussed on many other posts in Stack Overflow.
SortedMap
You could organize the StockRecord objects into a SortedMap, mapping the LocalDate to a Collection of the StockRecord objects sharing that particular date. Using a SortedMap rather than a mere Map lets you do smarter searches for a date range, as mentioned above. Again, many posts on Stack Overflow about maps.
Apache Commons CSV
By the way, Apache Commons CSV project makes easy work of reading and parsing a CSV data file.
BigDecimal
Do not use double or Double for currency amounts, or for any fractional number where accuracy matters. Those types are floating-point types, built for speed but trading away accuracy. You will be introducing extraneous extra digits into the end of the decimal fraction.
Instead use BigDecimal. Yet again, many posts on Stack Overflow on this class.
Integers
Do not use a fractional number like Double for an integer number such as your Volume field. Doing so wastes memory, and creates confusion to anyone reading your code.
Use a 32-bit integer or Integer if your maximum value is two billion or less (2^31-1 = 2,147,483,647), otherwise a 64-bit long or Long.

Related

How to create a large scale money conversion algorithm in java

I was just trying to create this small android app in android studio to convert currency.
I used 2 Spinner objects to hold only 3 values (USD, POUND, EURO) :
if(actualType.equals("USD")){
if(wantedType.equals("POUND")){
montantConv = montantNonConv * 0.87;
}
else if(wantedType.equals("EURO")){
montantConv = montantNonConv;
}
}
else if(actualType.equals("POUND")){
if(wantedType.equals("EURO")){
montantConv = montantNonConv * 1.15;
}
else if(wantedType.equals("USD")){
montantConv = montantNonConv * 1.15;
}
}
else if(actualType.equals("EURO")){
if(wantedType.equals("USD")){
montantConv = montantNonConv * 1;
}
else if(wantedType.equals("POUND")){
montantConv = montantNonConv * 0.87;
}
}
With if-else the code is too long for a combination of only 3 choices (input + output).
i was just wondering is there a better algorithm to do this ? How does the online ones do it that have 50+ currencies to chose from ?
As you are finding out, putting names of the currencies in the conversion logic is not a good idea. The same applies with the conversion values. You should want to write code to minimize things like that. You want the actual conversion logic coded without explicitly knowing ("hard coding") the names of the currencies or their exchange rates.
Rather than have something like actualType.equals("POUND") in your code, you want to try to have code that has each value represented by a variable: actualType.equals(otherType).
In real life, your data would come from an external source, such as a text file, a database, or another computer. In your small demo app, you might want to have the data load when the program starts, and be stored using array(s) and or (a) Collection object(s). At this time, you would also load the values in the Spinner objects, with the same data.
You might think about whether it is worth having another class or not:
class Money {
String name;
double conversionValue;
Money (String name, double value) {
this.name = name;
conversionValue = value;
}
And so on. (Note: I omitted visibility specifiers.)
In your conversion app, you could simulate the external source with an array:
Money [] market = { new Money ("Euro", 1.00), new Money ("USD", 1.00),
new Money ("Pound", 1.15), new Money ("Yen", 0.007),
new Money ("Rupee", 0.0125), ... };
An alternative to creating another class to glue a currency and exchange factor is to use a Map <String, Double>, with the name of the currency as the key and the exchange factor as the value.
So, the conversion app might have a method like this:
public double convertMoney (String selling, int amt, String buying)
{ ...
Depending on how the names and values were stored, it would use the string values to look up 2 conversion values. The exchange rate would be conversion value associated with selling divided by the conversion value associated with buying.

how to get user input (args) and pass it to a collection taking method

I've found an open source Java code that does IRR calculation. I would like to integrate this into my program. The idea is to input this java program some amounts and dates it then calculates IRR and returns a single number (double). The program excepts collection class as input (combination of numbers and dates) then returns the number. It can take as many number and dates as user wants. There are some sample code within the documentation, but all of them shows how this program gets parameters within the code hard coded. I'm trying to change it, so the program will get user input parse it into numbers and dates then ideally converts them into collection and pass it to the java program . I couldn't do it. I couldn't create collection object from user input and passed it to the program. I'm attaching sample code that does it values hardcodeded in the code, all I want to write a class that will dynamically capture user input (combination value and date, ideally one value, one date and so on) and pass it to the XIRR method.
public double xirr_issue5b() {
double rate = new Xirr(
new Transaction(-2610, "2001-06-22"),
new Transaction(-2589, "2001-07-03"),
new Transaction(-5110, "2001-07-05"),
new Transaction(-2550, "2001-07-06"),
new Transaction(-5086, "2001-07-09"),
new Transaction(-2561, "2001-07-10"),
new Transaction(-5040, "2001-07-12"),
new Transaction(-2552, "2001-07-13"),
new Transaction(-2530, "2001-07-16"),
new Transaction(-9840, "2001-07-17"),
new Transaction(38900, "2001-07-18")
).xirr();
return rate;
}
One thing to note is that the XIRR implementation in the open source package you refer to has public Xirr(Transaction... tx){ which (if you are not familiar with var args) means you can have any number of elements of transactions. What it also allows is for you to enter in an array. XIRR also can take in Collections (such as ArrayLists) So what I do in the following code is:
create a Scanner to read in the user input
Create a date formatter to convert the strings to dates
create an ArrayList that holds the transactions
An iteration counter based on user input
A for loop that loops the iterations amount predefined by the user and adds a new Transaction to the ArrayList each iteration taking in the user's next int and next String (converted to a date via date formatter).
I feed the ArrayList into the Xirr method.
Try this:
//import java.text.SimpleDateFormat;
//import java.util.ArrayList;
//import java.util.Date;
//import java.util.Scanner;
public double xirr_issue5b() {
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
Scanner sc = new Scanner(System.in);
ArrayList<Transaction> trans = new ArrayList<Transaction>();
int iterations = sc.nextInt();
for(int k = 0; k < iterations; k++) {
trans.add(new Transaction(sc.nextInt(), format.parse(sc.next())));
}
double rate = Xirr(trans).xirr();
sc.close();
return rate;
}

Android Joda Time, Having trouble sorting strings from ISOPeriodFormat

I've been looking everywhere for a solution but can't manage to find one that works.
I have a "Scoreboard" that needs to show the highest "times" (period between two instants) the app has calculated with Joda Time.
All the strings are stocked in an ArrayList and displayed through an ArrayAdapter and a ListView.
The problem : Collections.sort doesn't seem to work properly even with ISO format.
i'm saving the time using the format :
PeriodFormatter formatter = ISOPeriodFormat.standard();
Which gives out this : "PT1M15.664S"
(1 min 15seconds)
That i convert to a string and store into the ArrayList.
How can i sort these strings so it goes from the longest to the shortest amount of time in my Scoreboard ?
I've tried natural sorting and Alphanum Comparator with no luck. Every time it passes a cap (minutes, hours, days) the values get like this :
"PT2.455S"
"PT1.324S"
"PT1M15.333S"
Instead of what i would like :
"PT1M15.333S"
"PT2.455S"
"PT1.324S"
Using Collection.sort(myArrayList) doesn't work either.
Any idea what i should do ?
My code :
// set is a set<String> retrieving it's values from a stringset scores saved
in the sharedpreferences of the app
set = sharedPreferences.getStringSet("scores", null);
//scores is the ArrayList
scores.clear();
if (set != null){
scores.addAll(set);
}else{
scores.add("No Time Yet!");
set = new LinkedHashSet<String>();
set.addAll(scores);
sharedPreferences.edit().putStringSet("scores",set).apply();
}
//removing the String No Time Yet because it no longer serves a purpose here
if ((set != null)&& (set.size()>1)){
scores.remove("No Time Yet!");
}
arrayAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1,scores);
listView.setAdapter(arrayAdapter);
Collections.sort(scores);
Thank you for you time.
Short answer: Use the class Duration, not Period.
Explanation:
Your general approach using the class Period is wrong. This type represents a tuple of various amount-unit-pairs. Some of them are not convertible or comparable. For example, it is impossible to determine if P30D is greater or equal to or smaller than P1M (think of February, April or August). So it is pretty clear why you cannot sort by periods resp. why this class does not implement the interface Comparable. And this objection is valid for the objects of type Period as well as for its canonical ISO-representation (as String).
But since you want
the highest "times" (period between two instants)
you can use Duration to determine the absolute amount of elapsed seconds and milliseconds between two given instants. This type is comparable and only has two minor constraints which are probably not important for you:
precision limited to milliseconds
ignores leap seconds
I recommend to compare duration objects, not strings because you want a chronological order, not a lexicographical order. So you could use the String-representation of Duration (like PT72.345S) for storage but parse it for comparison:
Instant i1 = new Instant(0);
Instant i2 = new Instant(72_345);
Duration d1 = new Duration(i1, i2);
Instant i3 = new Instant(60_000);
Instant i4 = new Instant(200_710);
Duration d2 = new Duration(i3, i4);
List<String> scoreTimes = new ArrayList<>();
scoreTimes.add(d1.toString());
scoreTimes.add(d2.toString());
// order from longest times to shortest times
Collections.sort(
scoreTimes,
new Comparator<String>() {
#Override
public int compare(String s1, String s2) {
return Duration.parse(s2).compareTo(Duration.parse(s1));
}
}
);
System.out.println(scoreTimes); // [PT140.710S, PT72.345S]

JFreeChart TimeSeries array exception

this is my first question here ever, and I would appreciate if you can help me.
Since the code I have is way too large to post here, I'll try to describe what my problem is in short.
So, I have made TimeSeries array within my class and array list from where I get values for time series:
private TimeSeries[] seriesArray = new TimeSeries[10];
ArrayList<TempClass> valuesFromArrayList = new ArrayList<>();
I need to make TimeSeries array, because I want to be able to show multiple timeseries graphs. Using only one TimeSeries and addOrUpdate method isn't what I want because then values get mixed when I create more graphs. So, I add values like this:
for(int i = 0; i < valuesFromArrayList.size(); i++)
{
TempClass obj = (TempClass) valuesFromArrayList.get(i);
int timeStamp = obj.getTimeStamp();
int hrsDiff;
int minsDiff;
int secsDiff;
hrsDiff = timeStamp / 3600;
timeStamp = timeStamp - hrsDiff * 3600;
minsDiff = timeStamp / 60;
timeStamp = timeStamp - minsDiff * 60;
secsDiff = timeStamp;
seriesArray[Integer.parseInt(comboBoxValue) - 1].add(new Second(secsDiff, minsDiff, hrsDiff, day, month, year), Math.abs(obj.getValue()));
}
What this part of code does is that it reads values and timestamps from ArrayList I created. There is comboBox where user can choose which timeSeries array index will be in graph. So, if user chooses value 9 from comboBox, timeSeries from index 8 will be chosen and plotted on graph. TimeStamp is simply number of seconds that passed since 00:00:00 at day when values were taken.
TempClass is defined as:
class TempClass
{
private int timeStamp;
private double value;
public TempClass(int a, double b)
{
timeStamp = a;
value = b;
}
public int getTimeStamp()
{
return timeStamp;
}
public double getValue()
{
return value;
}
public void setValue(double val)
{
value = val;
}
}
The problem I have is that when I try to make second (2nd) graph, that is another index of TimeSeries array, I get message:
You are attempting to add an observation for the time period Thu Apr 30 00:00:00 CEST 2015 but the series already contains an observation for that time period. Duplicates are not permitted. Try using the addOrUpdate() method.
I don't want to use addOrUpdate method, I need add method. Values in ArrayList I use to put values into timeSeries are fine, I am 300% sure. I already checked input from comboBox value and it gives correct values.
I have no explanation other that for some reason, even if array index is changed, data I want to write into the series goes to the old series (that is, to the series at the old index). In other words, it seems like even if I change index of array, it keeps writing into the old array index!
It's like equivalent to this (I know this sounds crazy but that is basically what I am getting):
int[] array = new int[5];
array[0] = 1;
array[1] = 2;
System.out.println(array[0]);
And the output I get is
2
This is something I have never heard of before, and I have code similar to this I wrote here in two other places, and in that two places it goes just fine, but in this third place I keep getting that exception.
Is this some kind of bug in JVM?
Does somebody know what this could be?
I don't know too much about TimeSeries, but after skimming the docs about it it says:
"The time series will ensure that (a) all data items have the same
type of period (for example, Day) and (b) that each period appears at
most one time in the series."
Link to Docs
I'm guessing the error is pretty straight forward or a misuse of TimeSeries. It looks like you are simply adding a duplicate date and that the constraints of TimeSeries don't allow that.
You may wish to consider writing a custom class that has the functionality you want. Yet again, I don't know much about TimeSeries, but I hope this helped a little.
Your for loop will always overwrite the value with an index of 0 on seriesArray.
What I mean is, the first time it will write to [0]
The second it will write to [0] then [1]
Is this intended?
I have not looked at the docs too much, but the message says 'the series already contains an observation for that time period.' I think that loop is not doing what you want it to do.

Calculate average from sources that sends data at different time.

In my current project, I am going to write a function of calculating average Temperature.
A notatable point of this function is that it receives data from many temperature sources at different time. Could you advise me "How can I write a function with such a behavior?"
For instance, following function receives tempSensorData from many temperature Sensors, which sends temperature data at different time. I need to write a logic of calculating average temperature.
public void calculateRoomAvgTemp(TempStruct tempSensorData) {
// Write logic of calculating Average Temperature.
}
Why don't you just keep a running average? Assuming that your method gets called each time a temperature reading is taken, you can do the following:
private final List<Double> temps = Collections
.synchronizedList(new ArrayList<Double>());
private double currentAverage = 0d;
public void calculateRoomAvgTemp(TempStruct tempSensorData) {
synchronized (this.temps) {
this.temps.add(tempSensorData.temp);
this.currentAverage = 0d;
for (Double temp : this.temps) {
this.currentAverage += temp;
}
this.currentAverage /= this.temps.size();
}
}
can you store past temperatures in a separate field in the class? I noticed that your method is void, therefore doesn't return anything. I'm going to assume you want to store the average in the separate field. Example:
public class TempCalculator {
private double totalTemp = 0;
private int sensors = 0;
private double averageTemp = 0;
public void calculateRoomAvgTemp(TempStruct tempSensorData) {
totalTemp += tempSensorData.getTemp(); // Assuming getTemp() exists
sensors += 1;
averageTemp = totalTemp / sensors;
}
public double getAvgTemp() {
return averageTemp;
}
}
Of course, this can be done with a list if you want to store temperatures used and shaped to your needs. Hope this helps.
one way I could think of - insert values as you receive them into an ArrayList. If you need to calculate the average temperature after each data point that you receive, run through a for loop and average out the data points in the ArrayList to get the required value. One could look into using memoization to avoid running through the loop for all values.
Another option would be to use apache commons math whereby you can use the descriptive statistics option (using a rolling array) to get the mean (average).
I am assuming your code is single threaded. If multithreaded, you could use a thread safe vector (or add locks/synchronization on your own).
Hope this helps.
To calculate the average without keeping all historic values in memory (or a database), use a "moving average". This mathematical tool can give you the new average from the last one plus the current value.
You can create one thread which will calculate the temperature and many which will measure it values from different places. When some measurement is done the thread pushes the result into e.g. LinkedBlockingQueue. It's important to synchronize this operation because many threads might try to push results at the same time. The thread which calculate average temperature would run in a loop, pop new result from the queue, recalculate the temperature and then once again try to pop another result. As far as the queue will be empty the thread would be blocked on reading from it. In this way you would have an asynchronous communication between threads and the average temperature would be recalculated immediately after the measurements are done.

Categories

Resources