Compress rows with same id - java

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.

Related

Compare elements from an ArrayList

I have a small problem, I want to go through a list and compare two objects of the array. Each object has 3 elements, I use a StringTokenizer to be able to remove the separator, so each object has 3 elements. I would like to know how to make a method that gets the third element of each object and compare them. And if that element is less than another delete that element and the 2 before it.
I tried to make them with an iterator but I wouldn't know very well that it started from the 3 element and increased the position by 3.
Iterator<Integer> it = lisM.iterator();
int num;
while (it.hasNext()){
num = it.next();
System.out.println(num);
}
Is --> if, I was wrong to put it in the picture
This only answers part of your question. I could not understand the question completely, please edit it and I can edit my answer.
You should not remove items from a list whilst in a for loop, therefore you can, for example, create another boolean list with the same size divided by 3 and just fill it with true Booleans then set the position divided by 3 to false if you want to delete the three items. Then you can create a new list, iterate over the boolean list and add 3 "Objects" which are actually Strings (thanks #JB Nizet) at a time, every time the boolean list element is true. When it is false you just don't add the elements and by doing so you are practically deleting the two elements before that element together with that element.
You casted a String to an int, that does not work you have to parse the Strings.
I corrected some of your code and added the boolean list here:
ArrayList<String> lisM = new ArrayList<>(); // here I initialise the list as an array list with strings.
ArrayList<Boolean> booleanList = new ArrayList<>();
for (int i = 0; i < lisM.size() / 3; i++) {
booleanList.add(true);
}
for(int i = 3; i < lisM.size();i+=3) {
int m = Integer.parseInt(lisM.get(i)); // here I changed the casting to parsing and moved it out of the for loop, there is no need to initialize it again every single time since you do not change it in the second for loop.
for (int j = 6; j < lisM.size(); j += 6) {
int m1 = Integer.parseInt(lisM.get(j));// here I changed the casting to parsing again.
if (m > m1) { // this makes no sense here because you are going over all of the elements of the list and comparing them to all of them. But I kept it here for the sake of example.
booleanList.set(i/3,false);
}
// if you want to go over the whole list you will have to clear the list and start over again for every element.
}
}
and here is how you could create the new list without the elements you do not want:
ArrayList<String> newLisM = new ArrayList<>();
for (int i = 0; i <booleanList.size(); i++) {
if(booleanList.get(i))
for (int j = 0; j < 3; j++) {
newLisM.add(lisM.get(i+j));
}
}

Verifying the data from two arraylist and delete it

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());

Genetic Algorithm - Partially Mapped Crossover - Java

I'm working on something quite interesting, the TSP in Genetic Algorithms, more specifically looking at Partially Mapped Crossover. For background on the code, it receives two arrays of type int which correspond to the relevant cities so for example, first and second could be 1,2,3,4,5,6,7 and 2,3,4,5,2,4,3. What happens next is I try and cross over the cities without any duplication, however when I'm executing the while loop, it doesn't seem to be able to solve my issue as it gets stuck in an infinite loop.
Essentially, I'm baffled as to why it would get stuck in a loop when eventually it should just cross Over the city and get rid of all the duplicates, but for some reason I'm forever stuck in the while!
Background of code:
SIZE = size of cities in array, parent one and parent two contain random cities of size SIZE.
Any help would be greatly aprechiated!
private int[][] partiallyMappedCrossover(int first, int second){
//Used to return an array of type int
int[][] tempArray = new int[2][SIZE];
//Used to represent the selected individuals
ArrayList<Integer> parentOne = new ArrayList<Integer>();
ArrayList<Integer> parentTwo = new ArrayList<Integer>();
ArrayList<Integer> parentOneExchange = new ArrayList<Integer>();
ArrayList<Integer> parentTwoExchange = new ArrayList<Integer>();
//Used to generate crossOverPoints
ArrayList<Integer> crossOverPoints = new ArrayList<Integer>();
crossOverPoints.add(random.nextInt(SIZE));
crossOverPoints.add(random.nextInt(SIZE));
Collections.sort(crossOverPoints);
//Used for checking the parents contents
int currentCity = 0;
int arrayIndex = 0;
int newCity = 0;
//Assign the contents of the selected parents to my parentArrays
for(int i = 0; i < SIZE; i++){
parentOne.add(population[first][i]);
parentTwo.add(population[second][i]);
}
//used to gather cities from tours and swap between randomly selected crossoverpoints
for(int k = crossOverPoints.get(0) ; k < crossOverPoints.get(1) ; k++){
//declare ints to store the city value
int a = parentOne.get(k);
int b = parentTwo.get(k);
//excahnge cities between the two crossOverPoints
parentOneExchange.add(b);
parentTwoExchange.add(a);
}
for(int i = 0; i < crossOverPoints.get(0); i++){
//get the first city from the parentOne
currentCity = parentOne.get(i);
//Check the cities
if(parentOneExchange.contains(currentCity)){
//If it does contain the city, give one the index from the exchange
arrayIndex = parentOneExchange.indexOf(currentCity);
// get the city where we have a repitition
newCity = parentTwo.get(arrayIndex);
//if the new city is also a duplicated one, do another check
while(parentOneExchange.contains(newCity)){
// get the index of the city to replace the repeated city
arrayIndex = parentOneExchange.indexOf(newCity);
// get the city that is intended to replace the repeated city
newCity = parentTwo.get(arrayIndex);
}
//replace the duplicated city with the new city
parentOne.set(i,newCity);
}
currentCity = parentTwo.get(i);
if(parentTwoExchange.contains(currentCity)){
//If it does contain the city, give one the index from the exchange
arrayIndex = parentTwoExchange.indexOf(currentCity);
// get the city where we have a repitition
newCity = parentOne.get(arrayIndex);
//if the new city is also a duplicated one, do another check
while(parentTwoExchange.contains(newCity)){
// get the index of the city to replace the repeated city
arrayIndex = parentTwoExchange.indexOf(newCity);
// get the city that is intended to replace the repeated city
newCity = parentOne.get(arrayIndex);
}
//replace the duplicated city with the new city
parentTwo.set(i,newCity);
}
}
//loop the second crosschange
for(int i = crossOverPoints.get(1); i < SIZE; i++){
//get the first city from the parentOne
currentCity = parentOne.get(i);
//Check the cities
if(parentOneExchange.contains(currentCity)){
//If it does contain the city, give one the index from the exchange
arrayIndex = parentOneExchange.indexOf(currentCity);
// get the city where we have a repitition
newCity = parentTwo.get(arrayIndex);
//if the new city is also a duplicated one, do another check
while(parentOneExchange.contains(newCity)){
// get the index of the city to replace the repeated city
arrayIndex = parentOneExchange.indexOf(newCity);
// get the city that is intended to replace the repeated city
newCity = parentTwo.get(arrayIndex);
}
//replace the duplicated city with the new city
parentOne.set(i,newCity);
}
currentCity = parentTwo.get(i);
if(parentTwoExchange.contains(currentCity)){
//If it does contain the city, give one the index from the exchange
arrayIndex = parentTwoExchange.indexOf(currentCity);
// get the city where we have a repitition
newCity = parentOne.get(arrayIndex);
//if the new city is also a duplicated one, do another check
while(parentTwoExchange.contains(newCity)){
// get the index of the city to replace the repeated city
arrayIndex = parentTwoExchange.indexOf(newCity);
// get the city that is intended to replace the repeated city
newCity = parentOne.get(arrayIndex);
}
//replace the duplicated city with the new city
parentTwo.set(i,newCity);
}
}
//Assign the new offspring to the temp array for return
for(int i = 0; i<SIZE; i++){
tempArray[0][i] = parentOne.get(i);
tempArray[1][i] = parentTwo.get(i);
}
//return the contents of my tempArray
return tempArray;
}
Reading code to find errors like this is notoriously difficult and laborious. There are lots of easier ways you can find these types of errors. I'll give you four to consider (in my personal rough order of preference):
Split the various operations in your method into separate methods then write unit tests for each of those methods making sure they do exactly what you expect before moving onto the next. Once they are all working then you write a method that uses them all. Debugging a small method is much easier than debugging a large one.
Add assert statements that check that the conditions that you expect to be true actually are true. I'll give an example of that below.
An interactive debugger can find why your loop is not completing. That way you can see exactly what values the variables have at each point in your loop.
Add log statements to record interim values as the method progresses. This allows you to ensure expected conditions are met as the algorithm progresses.
Looking at one of your while loops:
while(parentOneExchange.contains(newCity)){
// get the index of the city to replace the repeated city
arrayIndex = parentOneExchange.indexOf(newCity);
// get the city that is intended to replace the repeated city
newCity = parentTwo.get(arrayIndex);
}
This will infinitely loop any time parentTwo.get returns a city that has been previously encountered. I expect that's what's happening due to a logic error earlier in the code. You could add an assertion to ensure that's not the case:
List<Integer> previous = new ArrayList<>();
while(parentOneExchange.contains(newCity)){
assert !previous.contains(newCity): previous;
previous.add(newCity);
arrayIndex = parentOneExchange.indexOf(newCity);
newCity = parentTwo.get(arrayIndex);
}
When this assertion fails you can see the list of previously visited cities and try to understand why it is looping.

Are for-loops conditions able to be changed midloop?

In java programming:
I have something along the lines of
ArrayList<String> list = new ArrayList<String>();
int listSize = list.size();
for(int x = 0; x< listSize; x++){
list.remove(x);
listSize = list.size();
}
will this work well enough? or will the for loop keep running. Thanks!
I'm a bit concerned at what you're attempting to do here. Any time someone wants to remove items from a collection in a loop without using an Iterator, alarms usually go off.
So, to answer the question as stated: If you change your loop invariant, then you'll get some funky behavior. This is why it's often called an "invariant"; you don't want to change it. You're certainly welcome to, but you're playing with fire here.
But, let's assume that we have a list of 5 elements in it and we execute your code as is.
List<String> stringList = Arrays.asList("word", "another word", "let's go", "keep it up", "get moving");
int length = stringList.size();
for(int i = 0; i < length; i++) {
System.out.println(stringList.remove(i));
length = stringList.size();
}
System.out.println("done");
If you're expecting it to print out every word in the list, then think again. It will skip every element because we are changing the content of the list while iterating over it. When deleting elements from an ArrayList, the underlying implementation will shift over elements to the left in where it was deleted. So, if you delete from position 0, every element now lives to the left of its original position (so element 1 is now element 0).
A quick run-through:
First iteration, i = 0; "word" is removed. Size is changed to 4, i increases to 1.
Second iteration, i = 1; "let's go" is removed. Size is changed to 3, i increases to 2.
Third iteration, i = 2; "get moving" is removed. SIze is changed to 2, i increases to 3.
No further iteration happens as the condition is not satisfiable.
If you want to cleanly remove all items from the collection without printing them out, then ArrayList#clear() is what you're looking for. If you want to remove elements one at a time, then use an Iterator instead:
List<String> stringList = new ArrayList<>(Arrays.asList("word", "another word", "let's go", "keep it up", "get moving"));
for(Iterator<String> stringIterator = stringList.iterator(); stringIterator.hasNext(); ) {
System.out.println(stringIterator.next());
stringIterator.remove();
}
System.out.println("done");
The loop won't keep running and it will end without any exception. But the result may not what you expect.
Besides "ArrayList#clear()" or Iterator way to remove all elements from one array. You can also try below codes, just remove "x++" from your loop condition.
ArrayList<String> list = new ArrayList<String>();
int listSize = list.size();
for(int x = 0; x< listSize;){
list.remove(x);
listSize = list.size();
}
Why not do it in a "while" loop?
ArrayList<String> list = new ArrayList<String>();
int listSize = list.size();
while(list.size() != 0){
list.remove(x);
}
Technically, the computer science course would likely tell you to do it something like this:
public void solve() {
ArrayList<String> list = new ArrayList<String>();
Iterator iter = list.iterator();
while(iter.hasNext()) {
System.out.println("Next value is: " + iter.next());
iter.remove();
}
}

Define array from another array

I'm trying to define an array starting from data that come from another array.
The code will explain the situation better than thousands words.
public class QualityCheck {
public QualityCheck (JTable table)
{
//the data come from a JTable (that represents a school timetable)
String [] dailyLessons= new String[table.getColumnCount()];
String [] dailyClasses= new String[table.getColumnCount()];
//checking all the days
for (int i=1; i<table.getColumnCount(); i++)
{
//checking all the hours in a day
for (int j=0; j<table.getRowCount(); j++)
{
//lesson is an array that contains the subject and the room in which the subject is erogated
//lesson[0] contains the subject
//lesson[1] contains the room
String[] lesson = ((TabellaOrario.MyTableModel)table.getModel()).getLesson(j,i);
//I'd like to put ALL the daily subjects in dailyLesson
dailyLessons[j] = lesson[0];
//I'd like to put All the daily rooms in dailyClasses
dailyClasses[j] = lesson[1];
}
//trying if dailyLessons has the elements
for (String s: dailyLessons)
{
System.out.println(s);
}
}
}
}
If a run this code, the compiler protest with this error:
Exception in thread "AWT-EventQueue-0" java.lang.ArrayIndexOutOfBoundsException: 7
and it evidence the string
dailyLessons[j] = lesson[0];
How can I do to define dailyLesson?
You are allocating both of the arrays to the same size table.getColumnCount(),
and then you use index j for both of them again, which goes up to table.getRowCount() - 1.
You probably should allocate one of them to size table.getRowCount(), and then use j as the index for only that one, and i for the other, but you never use dailyClasses so I'm not sure.
Edit:
Apparently the intent is to fill both the arrays with the data of one column. Then the fix is to change the size of the arrays to the amount of rows:
// Changed table.getColumnCount() -> table.getRowCount()
String [] dailyLessons= new String[table.getRowCount()];
String [] dailyClasses= new String[table.getRowCount()];
You init the arrays with table.getColumnCount() and loop using j < table.getRowCount().
If table.getColumnCount() is smaller that table.getRowCount() then you will get AIOBE.
You need at least to init the arrays with table.getRowCount().
EDIT
You could create a little class with encapsulates dailyLessons and dailyClasses
class Lesson {
public String dailyLesson;
public String dailyClass;
}
and create an array of that class, this way you'll always have the same number of daily lessons and classes:
String [] lessons = new Lesson [table.getRowCount()];
and later inside the loop:
lessons.dailyLesson = lesson[0];
lessons.dailyClass = lesson[1];
Also you could use an ArrayList instead of a simple array so you wont have to bother about the size of the array.

Categories