Verifying the data from two arraylist and delete it - java

I have a master arraylist call toBeDeleted which stored timestamp and email. The following are the sample data inside the toBeDeleted arraylist
[1507075234, bunny#outlook.com]
I have one arraylist call logData1 which stored status,email,timestamps and ID. The following are the sample data inside the logData1 arraylist.
[16, bunny#outlook, 1507075234, 0OX9VQB-01-00P-02]
I hope to delete the data inside the logData1 arraylist by verifying the timestamp first with timestamps stated in toBeDeleted1 arraylist, if the timestamp matched, I will check the email for both arraylist. If both of them are matched, I would like to delete away all the data (status,email,timestamp,ID). But I cant make it work
this is my sample output from my source code
[16, bunny#outlook.com, 1507075234, 0OX9VQB-01-00P-02]
The data inside toBeDeleted1 is :[1507075234, bunny#outlook.com]
The time1 is :1507075234
The email1 is :bunny#outlook.com
The time is :1507075234
The emails is :bunny#outlook.com
The data is :bunny#outlook.com
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: -3
at java.util.ArrayList.elementData(Unknown Source)
at java.util.ArrayList.get(Unknown Source)
at EmailReporting.main(EmailReporting.java:83)
This is my sample program
System.out.println(logData1);
System.out.println("The data inside toBeDeleted1 is :"+toBeDeleted1);
for(int v = 0;v<toBeDeleted1.size();v++) //look through the logdata1 for removing the record base on timestamp
{
String time1 = toBeDeleted1.get(v);
String email1 = toBeDeleted1.get(v+1);
System.out.println("The time1 is :"+time1);
System.out.println("The email1 is :"+email1);
for(int f = logData1.size();f>logData1.size()-1;f--)
{
// System.out.println(logData1.size());
// System.out.println("The data in logdata1 is "+logData1.get(f-2));
if(time1.equals(logData1.get(f-2)))
{
System.out.println("The time is :"+logData1.get(f-2));
System.out.println("The emails is :"+logData1.get(f-3));
if(email1.equals(logData1.get(f-3)))
{
System.out.println("The data is :"+logData1.get(f-3));
logData1.remove(f-1);
logData1.remove(f-2);
logData1.remove(f-3);
logData1.remove(f-4);
f-=4;
}
}
}
}
The error occurred after this line of code executed
System.out.println("The data is :"+logData1.get(f-3));

You can find elements in the list in order using Collections.indexOfSubList:
List<String> toFind = Arrays.asList(time1, email1);
int emailIndex = Collections.indexOfSubList(logData1, toFind);
A similar lastIndexOfSubList method also exists. That might be more appropriate for your use case.
You can then use this to remove the elements from toFind:
int emailIndex = Collections.lastIndexOfSubList(logData1, toFind);
if (emailIndex >= 1) {
logData1.subList(emailIndex-1, emailIndex+3).clear();
}
Just do this in a loop to keep going until all occurrences have been removed.
Note that just doing this in a loop naively will keep on searching over the tail of the list repeatedly. Instead, you can use subList to "chop" the end of the list, to avoid re-searching it:
List<String> view = logData1;
int emailIndex;
while ((emailIndex = Collections.lastIndexOfSubList(view, toFind)) >= 1) {
logData1.subList(emailIndex-1, emailIndex+3).clear();
view = logData1.subList(0, emailIndex-1);
}
Additionally, note that deleting from the middle of an ArrayList is inefficient, because the elements after the ones you delete have to be shifted down. This is why using subList(...).clear() is better, because it does all of those shifts at once. But if you are removing lots of 4-element batches, you can do better.
Instead of the subList(...).clear(), you can set the bits of elements to be deleted into a BitSet:
List<String> view = logData1;
BitSet bits = new BitSet(logData1.size());
int emailIndex;
while ((emailIndex = Collections.lastIndexOfSubList(view, toFind)) >= 1) {
bits.set(emailIndex-1, emailIndex+3);
view = logData1.subList(0, emailIndex-1);
}
And then shift all the elements down at once, discarding the elements you want to delete:
int dst = 0;
for (int src = 0; src < logData1.size(); ++src) {
if (!bits.get(src)) {
logData1.set(dst++, logData1.get(src));
}
}
And now truncate the list:
logData1.subList(dst, logData1.size());

Related

Compress rows with same id

Hi i'm trying to loop through this structure:
id string1 string2 different_string
1 test test asd
1 test test dsa
2 data data qwe
3 info info ewq
3 info info zxc
3 info info qaz
I have rows with the exact same value but one of them is different so I'm trying to compress that data into a single row.
This is my code:
int actual_id = list.get(0).num(); //I pick the first id = 1
ArrayList<ArrayList<String>> listOLists = new ArrayList<ArrayList<String>>();
ArrayList<String> items = new ArrayList<String>();
for(int i = 0; i < list.size(); i++){
if(list.get(i).id == actual_id){
String str = list.get(i).different_string;
items.add(str);
listOLists.add(items);
items.clear();
}else {
actual_id = list.get(i).id;
i--;
}
}
for(int j = 0; j < listOLists.size(); j++) {
System.out.println(listOLists);
}
First I check the id of each row and compare it with the actual value, I'm adding the string to an array and then append it to a list so I can store my data then reset the array to append new data to it and repeat the process, the problem is when I reset the array the loop doesn't seem to add more items to the list, what am I doing wrong?
this is I would like to get something like this:
{1, test, test, {asd, dsa}},{2, data, data, {asd}},{3, info, info, {ewq, zxc,qaz}}
Your code is a little difficult to follow but from what I can tell, your problem lies in this part of the code:
if(list.get(i).id == actual_id){
String str = list.get(i).different_string;
items.add(str);
listOLists.add(items);
items.clear();
}else {
You add items to listOList, but in the next line you clear it. items still refers to the List you just added to listOList so when you clear it, it clears the list in listOList as well. You may want to declare items within the if block so a new List will be created each pass through the loop like this:
if(list.get(i).id == actual_id){
ArrayList<String> items = new ArrayList<String>();
String str = list.get(i).different_string;
items.add(str);
listOLists.add(items);
}else {
This way, a new List is being created every iteration through the loop avoiding the issue. I can't tell if this will solve all you're problems but I hope this gets you headed in the right direction.

Read weighted graph from text file

I have to create a weighted graph from a text file. Below is a example how the text file looks like. The first number is the id of the actual train station. The second number is a possible destination and after the comma is the time in seconds, it takes to travel. The the third number is another possible destination.
060060101832 060063101842,78 060054104822,90
060054104822 060060101832,90 060057104812,90 060058101502,90 060054105611,66
060057104812 060054104822,90 060057102802,72
I want to store the routes in an ArrayList. Each route object should look like this:
Start: 060060101832
Destination: 060063101842
Time: 78
The problem is, I have to store multiple routes for the same starting location. How do I read the lines properly in, using a scanner? My approach was this:
while (routes.hasNext()) {
routes.useDelimiter(",| |\\n");
String start = routes.next();
String dest= routes.next();
String time= routes.next();
Edge edge = new Edge(start, dest, time);
edges.add(edge);
}
Since I cannot go back in the text file, I can't imagine how a right solution should look like.
This is not a complete code nor it was tested. It may or may not work but it will guide you anyways.
// Java 8
Node n;
Edge e;
String[] splittedLine;
String[] splittedEdge;
HashMap<String, Node> stationNumberToNode = new HashMap<>();
// if the file is not too large, you can read the file at once
List<String> lines = Files.readAllLines(new File("path/to/file.txt").getPath());
for(String line : lines){
splittedLine = line.split(" ");
if((n = stationNumberToNode.get(splittedLine[0]) == null){
n = new Node(splittedLine[0]); // assuming your Node has a constructor that takes the station id
stationNumberToNode.put(stationNumberToNode[0], n);
}
for(int i = 1; i < splittedLine.lenght; ++i){
splittedEdge = splittedLine[i].split(",");
e = new Edge(splittedEdge[0], splittedEdge[1]); // assuming your Edgehas a constructor that takes the destination station and the cost
n.addEdge(e);
}
}
Explanation
Node n;
Edge e;
String[] splittedLine;
String[] splittedEdge;
HashMap<String, Node> stationNumberToNode = new HashMap<>();
Ideally you should always declare variables outside loops, so you avoid allocating a new memory on every iteration. Thus, we declare our 5 variables before entering the loop. The HashMap is used here to cover the case that your input is not always grouped and you avoid having to perform a list search everytime.
List<String> lines = Files.readAllLines(new File("path/to/file.txt").getPath());
Read all the lines on the file at once. Alternatively, as requested on the question, you can read the file using Scanner like on this anwer. You have to change the way you iterate over the lines, though.
splittedLine = line.split(" ");
Splits the line on the " ", since your input file is well formated.
if((n = stationNumberToNode.get(splittedLine[0]) == null){
n = new Node(splittedLine[0]); // assuming your Node has a constructor that takes the station id
stationNumberToNode.put(stationNumberToNode[0], n);
}
Checks if the current node is already on the HashMap. If yes, it will be stored in the variable n. Else, it will create a Node with the current id and add it to our HashMap.
for(int i = 1; i < splittedLine.lenght; ++i){
splittedEdge = splittedLine[i].split(",");
e = new Edge(splittedEdge[0], splittedEdge[1]); // assuming your Edgehas a constructor that takes the destination station and the cost
n.addEdge(e);
}
Since everything in the input file is the destination station and its cost (id,cost), we iterate on the splittedLine from index 1 onwards.
For every edge data, we split based on "," (from your input file), whereas splittedEdge[0] will be the destination id and splittedEdge[1] will be the cost to that destination. We create an Edge with that information and add that Edge to the Node object.

Java - Trouble reading data from a list of 2D arrays

I have created a list of 2D arrays containing randomly generated number values for different locations.
public static int Prices[][] = new int[Cities.length][ItemNames.length];
public static List<int[][]> CityPrices = new ArrayList<int[][]>();
public static void NewDay()
{
for(int i = 0; i<Cities.length; ++i)
{
Prices[i] = PriceGenerator.ReturnPricesForCity(i);
//This method returns an array of random integers
}
CityPrices.add(Prices);
}
But then later when I want to retrieve the price history for a specific item for the amount of days passed, it returns the same value for each day
int Prices[] = new int[GlobalVariables.CityPrices.size()];
String sTest = "";
for(int i = 0; i < Prices.length; ++i)
{
Prices[i] = GlobalVariables.CityPrices.get(i)[spinCity.getSelectedItemPosition()][spinItem.getSelectedItemPosition()];
sTest = sTest + Prices[i] + ",";
}
In this case, the values returned by sTest was : 6055,6055,6055,6055,6055, for five consecutive days.
If I would for instance add a day, the values would change to a range of a new number, which in this case was : 7294,7294,7294,7294,7294,7294,
Please show me what I am doing wrong, as I have been trying to figure this one out the past 4 days with no luck.
Every element in your CityPrices list is the same: in each case, you are adding the Prices two-dimensional array. Your loop modifies Prices[i], but it doesn't change Prices, which is still a reference to the same two-dimensional array right the way through.
I think you're imagining it will pass the contents of the array in its current state, but it doesn't: it passes a reference to the array to the .add() method, so any subsequent changes to the array will be reflected in the contents of CityPrices.
If at the end of your loop you try
CityPrices.get(0) == CityPrices.get(1)
you'll see it returns true.
In the assignment: Prices[i] = GlobalVariables.CityPrices.get(i)[spinCity.getSelectedItemPosition()][spinItem.getSelectedItemPosition()]; you are basically referencing an int[][] at the same index for both dimensions.
On top of that, the spinCity.getSelectedItemPosition() invocation might be returning the same index at every iteration of your loop, hence your identical values.
It's hard to assume anything further as you haven't posted the code for spinCity.

Aggregating objects by timestamp per day for a timespan of week

I have problem with aggregating data based on their timestamp per day for a timespan of one week. There is a SQLite database, which has a table which I save the number of walking steps in (timestamp column is UTC and created_At is local time, but I don't use the created_at column anyway).
What I want to do is get the total data which happened in 7 days ago until the midnight of a day before. So I have this jodatime expression to find start and end for timestamps
long start = new DateTime().withMillisOfDay(0).minusDays(7).getMillis();
long end = new DateTime().withTimeAtStartOfDay().getMillis();
//start milli:1405029600000 DateTime: 2014-07-11 00:00:00
//end milli:1405634400000 DateTime: 2014-07-18 00:00:00
Then I execute this sql command:
SELECT * FROM pa_data WHERE timestamp BETWEEN 1405029600000 AND 1405634400000
And I am pretty sure that it returns the correct rows ( I have compared the android database result with SQLite Database Browser on my pc, both return same number of rows). For this, I tried to use this nested iteration:
the Object I am trying to create is:
public class PhysicalActivityPerDay {
private List<PhysicalActivity> mList;
public PhysicalActivityPerDay(List<PhysicalActivity> list) {
mList = new ArrayList<PhysicalActivity>(list);
}
//methods....
}
Now the problem is, I want to have a data object that can hold the rows for each day.
List<PhysicalActivity> all = getPhysicalActivitiesBetween(start, end);
List<PhysicalActivityPerDay> perDays = new ArrayList<PhysicalActivityPerDay>();
List<PhysicalActivity> tempList;
PhysicalActivityPerDay tempPerDay;
for (int i = 0; i < 7; i++) {
long begin = start;
long stop = (begin + 86400000); //add 24 hours
tempList = new ArrayList<PhysicalActivity>();
for (int j = 0; j < all.size(); j++) {
PhysicalActivity p = all.get(j);
DateTime when = new DateTime(p.getTimestamp());
if (when.isAfter(start) && when.isBefore(stop)) {
tempList.add(p);
all.remove(j); //remove the matching object from the list
}
}
tempPerDay = new PhysicalActivityPerDay(tempList);
perDays.add(tempPerDay);
start += 86400000; //add 24 hours or 1 day for next iteration
}
return perDays;
But the result is totally unexpected. There are many rows which don't match the if statements above. I did a debug and here is what happens:
Log.w(TAG, "There are totally " + all.size() + " physical activities for day for 7 days");
//There are totally 6559 physical activities for day for 7 days
But, when I check the all list (total rows returned by DB) although I am removing matched objects from it, if I query its size after the nested iteration, it surprisingly still contains many objects in it, telling me that the iteration was not successful!
//Remaining: 3278 records after iterations from 6559
What I am doing wrong? please help me findout!
Not sure if that's the only problem :
You are looping over the all List, and removing items.
When you call all.remove(j), the item that used to be at position j+1 moves to poisition j. Which means your for loop would skip that item.
One way to solve this is to increment j only if you don't remove an item from the list.
for (int j = 0; j < all.size();) {
PhysicalActivity p = all.get(j);
DateTime when = new DateTime(p.getTimestamp());
if (when.isAfter(start) && when.isBefore(stop)) {
tempList.add(p);
all.remove(j); //remove the matching object from the list
} else {
j++;
}
}
Actually, I'm not entirely sure if the loop would work after this fix. It depends whether all.size() is evaluated in each iteration. If it isn't, it would expect the list to have the initial number of elements, even though you are removing items. In that case you can expect to get an exception the first time you try to access an index beyond the last index of the array.
If you get an exception, you can replace the loop with a while loop :
Iterator<PhysicalActivity> iter = all.iterator();
while (iter.hasNext ()) {
PhysicalActivity p = iter.next();
...
if (...) {
iter.remove();
}
}
Refer to the definition of List.remove() :
public E remove(int index)
Removes the element at the specified position in this list. Shifts any subsequent elements to the left (subtracts one from their indices).
How about letting SQL perform your aggregation for you
SELECT strftime('%W-%Y',dt) as weekYear, count(1) as occurencePerWeek
FROM SOMETABLE c GROUP BY weekYear;
http://sqlfiddle.com/#!5/e63c3/1

Inputting object in correct position of Linked List

I have a csv file with a few rows (group #, # of elements in group, element #) and I need to place these inside of a Linked List. I have this happening while the csv is being read in by the file, putting it into the tmpPacket object, then placing the tmpPackets into the nodeList (linked list) and am trying to have it adding to the Linked List in order so if the group # is the same as a previous one, it adds it to the beginning of that group, otherwise to the end of the linked list.
Anyways, I have it so far working to the point where it will add one group # to the Linked List, but ignores the rest of the groups. example input would be:
4,3,2
5,1,1
4,3,1
4,3,3
2,2,2
3,1,1
2,2,1
and basically I want it so when it is added to the linked list it will look like:
4,3,1
4,3,2
4,3,3
5,1,1
2,2,1
2,2,2
3,1,1
(the exact order doesn't matter. 4, 5, 2, and 3 can be in any order, important is that the 4's are together, 5's are together...).
Here is what I have that is only outputting the 4's and nothing else.
int currLength = nodeList.getLength();
int finishNum = 0;
for(int tmpGo=1;tmpGo<=currLength;tmpGo++){
if(finishNum == 0){
int itr = 0;
int addEnd = 0;
while(itr<nodeList.getLength()){
itr++;
if(nodeList.getEntry(itr).getPageID() == pageID) {
nodeList.add(tmpGo, tmpPacket);
finishNum = 1;
addEnd = 1;
break;
}
}
} else {
break;
}
}
So, I don't know what your nodeList is, but according to your initial description you would need this:
int i;
int l = list.length();
for (i = 0; i < l; i++)
if (list.getEntry(i).key() == newKey)
break;
list.insert(newEntry, i);
This example assumes:
List entries are numbered from 0 until length - 1
Inserting an entry at the length is the same as appending it
However, it will not result in your sample result. Instead you will get:
4,3,3
4,3,1
4,3,2
5,1,1
2,2,1
2,2,2
3,1,1

Categories