Removing items from list by index while looping through list - java

public boolean isTwoPair() {
boolean isTwoPair = false;
Collections.sort(deck);
List<Card> cards = new LinkedList<Card>(deck);
System.out.println(cards);
for (int i = 0; i < cards.size()-1; i++) {
for (int j = i + 1; j < cards.size()-1; j++) {
if (deck.get(i).equals(deck.get(j))) {
cards.remove(i);
cards.remove(j);
System.out.println(cards);
}
}
}
return isTwoPair;
}
I think my problem is with my cards.remove(). When I remove a card, the next time the card is removed it removes it from an altered list. Is there a way to remove two items from a list while they have the same index numbers?
If I have to remove index 0,1 because they are both pairs like so:
[Ace,Ace,Three,Four,Four]
the code removes it like this(removing index 0)
[Ace,Three,Four,Four]
than instead of removing the index 1(Ace) from the first list it removes it from the second list so
[Ace,Four,Four]
It removed the index 1 from the second list which was three.
This is what I was expecting
[Three,Four,Four]
At this point I expect my loop to pick up and remove Four and Four
EDIT:
public boolean isTwoPair() {
boolean isTwoPair = false;
Collections.sort(deck);
List<Card> cards = new LinkedList<Card>(deck);
System.out.println(cards);
for (int cardOne = 0; cardOne < cards.size(); cardOne++) {
for (int cardTwo = cardOne + 1; cardTwo < cards.size(); cardTwo++) {
if (deck.get(cardOne).equals(deck.get(cardTwo))) {
cards.remove(cardOne);
cards.remove(cardTwo-1);
System.out.println(cards);
for(int cardThree = 0; cardThree < cards.size(); cardThree++){
for(int cardFour = cardThree+1; cardFour < cards.size(); cardFour++){
if(cards.get(cardThree).equals(cards.get(cardFour))){
cards.remove(cardThree);
cards.remove(cardFour-1);
System.out.println(cards);
isTwoPair = true;
}
}
}
}
}
}
return isTwoPair;
}
this is what I am using now, I didn't really want to make a new variable if I didn't have to so I decided to not remove Object

If you know j is always greater than i (because of the for loop), if you delete the element with index i first then you can delete the element with index j - 1 getting the expected result.
cards.remove(i);
cards.remove(j-1);

Use List.remove(Object) instead of List.remove(int). That will not depend on the ordering of the List anymore.
public boolean isTwoPair() {
boolean isTwoPair = false;
Collections.sort(deck);
List<Card> cards = new LinkedList<Card>(deck);
for (int i = 0; i < cards.size()-1; i++) {
for (int j = i + 1; j < cards.size()-1; j++) {
cardI = deck.get(i);
cardJ = deck.get(j);
if (cardI.equals(cardJ)) {
cards.remove(cardI);
cards.remove(cardJ);
isTwoPair = true;
}
}
}
return isTwoPair;
}

The problem is that when you remove an object from the list you are not accounting for the fact that the size is not the same after removal and that indices of elements are changed after removal
Suppose you want to remove elements at and 0 and 1
initially => [Ace,Ace,Three,Four,Four]
0 1 2 3 4
remove [0]
after removing [0] => [Ace,Three,Four,Four]
0 1 2 3
remove [1]
after removing [1] => [Ace,Four,Four]
0 1 2
Thus you cant us indices for removal, instead use List.remove(Object)

cards.remove(i);
cards.remove(j);
As soon as you remove an element from the LinkedList, it shifts any subsequent elements to the left (subtracts one from their indices). You could use j-1 instead of j if j > i. Or, cards.remove(Card) instead.

Related

Why is my ArrayList empty after adding new objects?

Why is this ArrayList empty when I print it out?
ArrayList<InterviewQuestion> interviewQuestionArrayList = new ArrayList<>();
for (int i = 0; i <interviewQuestionArrayList.size(); i++) {
interviewQuestionArrayList.add(new InterviewQuestion());
}
System.out.println(interviewQuestionArrayList);
You have created arraylist but before adding you are trying to looping through it.. size will be zero initially..
If you know how many interviewQuestions are there then you can loop with that number.
ex:
for (int i = 0; i <numberOfQuestions; i++) {
interviewQuestionArrayList.add(new InterviewQuestion());
}
numberOfQuestions should be predifined..
Initially if you dont know how many times you want to add then you can use while loop. But you should exit from while based on some condition
like,
boolean flag = true;
while(flag) {
interviewQuestionArrayList.add(new InterviewQuestion());
if(condition) flag = false;
} //something like this
As far as i can see, your List is empty when you enter the loop.
Thus its size() will return 0 and the loop will not add any elements.
your code basically does
for (int i = 0; i < 0; i++) {
interviewQuestionArrayList.add(new InterviewQuestion());
}
Here you create an empty list -> this means the size is currently 0
ArrayList<InterviewQuestion> interviewQuestionArrayList = new ArrayList<>();
The following loop is never executed because i (now 0) is never < size (now 0)
This means there are no Objects added to your list
for (int i = 0; i <interviewQuestionArrayList.size(); i++) {
interviewQuestionArrayList.add(new InterviewQuestion());
}
Try using i<10 as the condition in the for loop to add 10 elements to the list
if this 2 staments are followed by each other, then your list is never populated:
ArrayList<InterviewQuestion> interviewQuestionArrayList = new ArrayList<>();
for (int i = 0; i <interviewQuestionArrayList.size(); i++) {
interviewQuestionArrayList.add(new InterviewQuestion());
}
ergo, you have an empty list to print
System.out.println(interviewQuestionArrayList);
you can play with some dummyData that you add when declaring the list

Finding index of an item within a 2D Array

After some research, I found out how to find the index of an item within a 2D Array. However, I'm after just one value, the row number and also what if the item you are looking for appeared more than once?
How would you store the row number of all those times?
for(int j = 0; j < size; j++)
{
if (arr[i][j] == 88)
{
return i; // The value i wanna store
break;
}
}
If the number 88 appears more than once, how can I store all the different locations and later retrieve it?
You could store the values you want in a List.
List<Integer> rows = new ArrayList<>();
for (int i = 0; i < size; i++) {
for (int j = 0; j < size; j++) {
if (arr[i][j] == 88) {
rows.Add(i); // The value i wanna store
break; // exit inner loop and continue with next row
}
}
}
i'm after just one value, the row number
But if 88 appears more than once, how can I store all the different
locations and later retrieve it?
Considering you don't know how many duplicated copies of the value you're looking for there could be, I'd suggest using an ArrayList to store the indexes.
create this before the loops:
List<Integer> indexList = new ArrayList<>();
then within the if block simply add the index value for the value you've found to the ArrayList:
if (arr[i][j] == 88){
indexList.add(i);
break;
}
you can then return the ArrayList if your method requires returning the data:
return indexList; // after the loops have finished processing
However, if the method return type is void then you can simply ignore the return indexList;

Merging two sorted ArrayLists

I am supposed to create a method that will merge two given pre-sorted ArrayLists of Strings into one. All of it has to be done in one loop. The way I have gone about it is comparing the two ArrayLists at each index and adding them in alphabetical order based on those comparisons. The problem with this is that if you are given two ArrayLists ["Bob", "Jill"] and ["Watson", "Zane"], the output would be ["Bob", "Watson", "Jill", "Zane"]. This is clearly not sorted.
That being said, I know what the problem is, I just don't know how to implement a fix for it.
Code:
public static ArrayList<String> merge(ArrayList<String> al1, ArrayList<String> al2){
ArrayList<String> al = new ArrayList<String> (al1.size() + al2.size());
for (int i = 0; i < Math.max(al1.size(), al2.size()); i++) { // Loops until max size of the two arraylists is reached
if (i < al1.size() && i < al2.size()) { // Checks if the index is still in range of both arraylists
if (al1.get(i).compareTo(al2.get(i)) < 0) { // Compares the two arraylists at the same index
al.add(al1.get(i));
al.add(al2.get(i));
} else {
al.add(al2.get(i));
al.add(al1.get(i));
}
} else if (i < al1.size() && i > al2.size()) { // Checks if the index is greater than the size of al2
al.add(al1.get(i));
} else { // Anything else, just add al2
al.add(al2.get(i));
}
}
return al;
public static ArrayList<Double> merge(ArrayList<Double> a, ArrayList<Double> b) {
ArrayList<Double> toReturn = new ArrayList<Double>();
int a_ = 0;
int b_ = 0;
for(int j = 0; j < a.size() + b.size(); j++) {
if(a_ == a.size())
toReturn.add(b.get(b_++));
else if(b_ == b.size())
toReturn.add(a.get(a_++));
else if(a.get(a_).compareTo(b.get(b_)) < 0)
toReturn.add(a.get(a_++));
else
toReturn.add(b.get(b_++));
}
return toReturn;
}
You're using one index, i, to index into both a1 and a2, which means that you can't move through the two lists independently. As you've noticed, a pair of lists like [1, 2, 3] and [4, 5, 6] should be merged by taking all three elements from the first list and then taking the elements from the second list. By traversing both lists simultaneously as you're doing that's not possible.
Instead track two separate indicies, say i1 and i2, and increment them independently. At each iteration determine which index is smaller, add that value and increment that index. Once you've reached the end of one list or the other you just drain the remaining list.
You shoud take a look at merge step of merge-sort algo:
https://en.wikipedia.org/wiki/Merge_sort
All in all you should have something like:
int i = 0;
int j = 0;
while (i < a.size() && j < b.size()) {
if (a.get(i).compareTo(b.get(j)) <= 0) {
result.add(a.get(i));
++i;
} else {
result.add(b.get(j));
++j;
}
}
for (; i < a.size(); ++i) {
result.add(a.get(i));
}
for (; j < a.size(); ++j) {
result.add(b.get(j));
}
return result;
Didin't test it, however in result you should have something that looks the same

Java 2D array encirclement

I am tasked to make a program which returns true if in a 2D array 1-s encircle 0-s.
I tried something like this, but i cant find the right solution.
public boolean checkGameState(){
for(int i=0;i<fields.length;i++){
for(int j=0;j<fields.length;j++){
if(fields[i][j]!=0){
if(row(i,j){
return true;
}
}
}
}
return false;
}
private boolean row(int a, int b){
int checkI=a;
int checkJ=b;
while(fields[checkI][checkJ]==1){
checkJ++;
}
while(fields[checkI][checkJ]==1){
checkI++;
}
while(fields[checkI][checkJ]==1){
checkJ--;
}
while(fields[checkI][checkJ]==1){
checkI--;
}
return a==checkI && b==checkJ;
}
The 2D array looks something like this:
111100
100100
100101
111100
001100
For this array the method should return true.
The easiest way might be to use a flood fill algorithm to eliminate all the zeros that are not encircled by ones, and then checking whether there are any left.
First, put all the zeros directly on the "fringe" of the 2D array into a queue. Then, use the flood fill algorithm to turn all of those into a different number (e.g., 2), and add the nodes next to them to the fringe set (either diagonally or only direct neighbours). Repeat until there are no more nodes in the fringe. Finally, check whether there are any more zeros in the array. If so, those were not connected to the fringe region and thus had to be "encircled" by ones.
// test data set up
int[][] data = {{1,1,1,1,0,0},
{1,0,0,1,0,0},
{1,0,0,1,0,1},
{1,1,1,1,0,0},
{0,0,1,1,0,0}};
int N = data.length, M = data[0].length;
// create queue of zeros on the "fringe"
Queue<int[]> fringe = new LinkedList<>();
for (int i = 0; i < N; i++) {
if (data[i][0 ] == 0) fringe.add(new int[]{i,0 });
if (data[i][M-1] == 0) fringe.add(new int[]{i,M-1});
}
for (int j = 0; j < M; j++) {
if (data[0 ][j] == 0) fringe.add(new int[]{0 ,j});
if (data[N-1][j] == 0) fringe.add(new int[]{N-1,j});
}
// do flood fill until no more zeros reachable
while (! fringe.isEmpty()) {
int[] next = fringe.poll();
int i = next[0], j = next[1];
data[i][j] = 2;
for (int di = -1; di <= 1; di++) {
for (int dj = -1; dj <= 1; dj++) {
try {
if (data[i+di][j+dj] == 0) fringe.add(new int[]{i+di, j+dj});
} catch (ArrayIndexOutOfBoundsException e) {}
}
}
}
// check for remaining zeros
boolean encircled = false;
for (int i = 0; i < N; i++) {
for (int j = 0; j < M; j++) {
System.out.print(data[i][j]);
encircled |= data[i][j] == 0;
}
System.out.println();
}
System.out.println(encircled);
Example output:
111122
100122
100121
111122
221122
true
The complexity should be on the order of O(NxM), since each of the NxM nodes can only appear once in the queue (plus a bit of overhead for constructing the queue and finding remaining zeros).
Please note that I have assumed that you need rectangle shape surrounding
You need to find sequences for 3 or more 1 in one row.
xx1111xx // x means any number
For each sequence check if there is sequence of the same length 2 or more rows lower.
xx1111xx
xxxxxxxx
xx1111xx
For each "pair" of sequences check if they are connected with 1 on the edges.
xx1111xx
xx1xx1xx
xx1111xx

Gets the number of duplicates in the list - wrong output

How to count duplicates in ArrayList and count only once.
Here is what I have so far:
/**
* Gets the number of duplicates in the list.
* Get the next word. It is at index i. Does it match any of the words with index > i?)
* #return the number of duplicate words in the list
*/
public int countDuplicates() {
int duplicates = 0;
for (int i = 0; i < list.size(); i++) {
for (int j = i; j < list.size(); j++) {
if (list.get(i).equals(j)) duplicates++;
}
}
return duplicates;
}
Here is check output:
Actual: 0
Expected: 3
I am missing something very easy. However, couldn't find what exactly it is.
How to solve this trouble?
You don't get the jth element you just compare to j directly. And as a commenter points out, j should start at i+1 to avoid comparing an element to itself. Therefore, you need to write
public int countDuplicates()
{
int duplicates = 0;
for (int i = 0; i < list.size(); i++) {
for (int j = i+1; j < list.size(); j++) {
if (list.get(i).equals(list.get(j))) duplicates++;
}
}
return duplicates;
}
Should be:
public int countDuplicates()
{
int duplicates = 0;
// TODO: Write the code to get the number of duplicates in the list
for (int i = 0; i < list.size(); i++) {
for (int j = i + 1; j < list.size(); j++) {
if (list.get(i).equals(list.get(j))) duplicates++;
}
}
return duplicates;
}
Use two sets for this:
final Set<X> set = new HashSet<>();
final Set<X> dups = new HashSet<>();
int dupCount = 0;
for (final X x: list) {
if (set.add(x)) // first time the element is seen
continue;
// Dup; see whether it is the first time we see it
if (dups.add(x))
dupCount++;
}
return dupCount;
This relies on the fact that Set's .add() returns true if and only if the set has been modified as the result of the operation. And note that it traverses the list only once.
I can see three problems with your current code:
You are not comparing pairs of elements. You are actually comparing an element with an index.
Your inner loop is comparing element i and element i ... and that would result in a false "duplicate" count.
If you have more than 2 copies of any given element, then you will get too many duplicate counts. (To see why, try to "hand execute" with a list of (say) three identical elements.
In fact, you have to EITHER use an auxiliary data structure (e.g. 2 Sets or a Map) OR modify the input list to avoid counting duplicates more than once.
I would note that your statement of the problem is ambiguous. "... only count each duplicate once" could mean that '[1, 1, 1]' gives either 1 or 2. It depends whether you consider each individual 1 to be a duplicate to be counted once or that we have 1 as one of a set of duplicates ... that must only be counted once.
You are comparing index j value instead of value of list list.get(j).
Do
if (list.get(i).equals(list.get(j)))
instead of
if (list.get(i).equals(j))

Categories