I am having problems with making a method that will return distinct integers of the array list. I really want to do it with removing the duplicates and then just display the array list. I cannot figure out what is the problem. When I test it out this is the output I get: [3, 11, 33, 10]
This is my code
package getUniques;
import java.util.ArrayList;
public class Uniques {
public static ArrayList<Integer> getUniques( ArrayList<Integer> list ){
int i = 0;
while(i < list.size() - 1){
for (int j = 0; j < list.size(); j++){
if (list.get(i) == list.get(j))
list.remove(i);
}
i++;
}
return list;
}
public static void main(String[] args) {
ArrayList<Integer> list = new ArrayList<Integer>();
list.add(3);
list.add(3);
list.add(5);
list.add(11);
list.add(22);
list.add(33);
list.add(22);
list.add(10);
System.out.println(getUniques(list));
}
}
You can also get unique values by using Set. Insert the values in a Set and then put it back into an ArrayList like new ArrayList(theSet);
Changing the list as you iterate over it is always going to cause pain!
Say you remove item 3 (so the old 4th becomes the new 3) - then you do i++, so you are effectively skipping the "old 4th" element.
You can skip the i++ if you removed the item to get back on track, but a some other
solutions:
Use a Set or similar in the first place so you can't get duplicates.
Use a second list to hold the values (or indexes) of items you want
to remove (if using indexes, you can remove them highest to lowest
else you end up with the same issue: delete index 1, index 4 is now
index 3...)
Flip your search so you are going back towards 0, same principal
applies. You can remove high indexes without impacting lower ones.
Make your outer loop use an iterator so you can use the remove operation.
Your code has a few problems. Here's fixes for your existing code:
First you are removing the wrong index. You've identified the element at j as the duplicate; remove it instead of the element at i.
list.remove(j); // j not i
Next, you are removing all elements that are the same, and you aren't leaving the "original". To fix this, only test (and remove) those that are past i in the loop.
for (int j = i + 1; j < list.size(); j++){ // Start at i + 1, not 0.
Then you'll need to retry your j index once you've removed it, because the rest of the elements have been shifted backwards 1 spot. Instead of
if (list.get(i) == list.get(j))
list.remove(i);
Try
if (list.get(i) == list.get(j))
{
list.remove(j);
j--; // Try this j again next loop, once it's incremented again.
}
To remove items while iterating, you have to use an iterator, as it guarantees the order:
Iterator<Integer> iterator = list.iterator();
int i = 0;
List<Integer> listCopy = new ArrayList<Integer>(list);
while(iterator.hasNext()){
i++;
Integer value = iterator.next()
for (int j = i; j < listCopy.size(); j++){
if (value.equals(listCopy.get(j))) {
iterator.remove();
}
}
}
However, in this case, as you need to iterate twice through the same list, it's not the best solution. It might be faster putting everything into a sorted Set, as Set removes duplicates on its own.
Related
List<List<Integer>> myList = new ArrayList<>(3);
for(int i=0; i < 3; i++) {
myList.add(new ArrayList());
}
myList.get(0).add(1); // 0,0
myList.get(0).add(4); //0,1
myList.get(1).add(2); // 1,0
myList.get(1).add(5); // 1,1
myList.get(2).add(3);// 2,0
myList.get(2).add(6); //2,1
myList.get(2).add(7); //2,3
for(int i =0; i<myList.get(i).size(); i++){
for(int j=0; j<myList.size(); j++){
System.out.println(myList.get(j).get(i));
}
}
I cant figure out how to iterate through the list on a index based, with different lengths on each list. My code above only works if all lists are the same size.
Ideal output would be:
1
2
3
4
5
6
7
But I cant figure out how to print out 7 since that list is a different length. This might be a very simple solution and ill probably feel dumb after. Thanks guys
To iterate over all elements of List of Lists you need to iterate in the first for-loop over the outer List, and in the second for-loop over the inner loop at that index. There are several possibilities to achieve the iteration over all elements, as you will see in the following examples.
(Your code would also produce a IndexOutOfBoundsException for the last entry).
Iterating through a List of Lists
Option 1 (your code corrected)
for (int i = 0; i < myList.size(); i++) { // i represents index of outer List
for (int j = 0; j < myList.get(i).size(); j++) { //j represents index of the inner list at index i
System.out.println(myList.get(i).get(j));
}
}
Option 2 (using for-each loop)
for (List<Integer> innerList : myList) {
for (Integer currentPosition : innerList) {
System.out.println(currentPosition);
}
}
Option 3 (using streams)
myList.stream()
.flatMap(Collection::stream)
.forEach(System.out::println);
}
Edit due to comment: added traverse method for wanted output
If you want to print out all first entries of the inner lists first, a possibility would be to traverse your List<List<Integer>> with a method like this (method is generic, would also work with other classes):
private static <T> List<List<T>> traverse(List<List<T>> input) {
List<List<T>> result = new ArrayList<>();
for (int i = 0; i < input.size(); i++) {
for (int j = 0; j < input.get(i).size(); j++) {
if(result.size() <= j) {
result.add(new ArrayList<>());
}
result.get(j).add(input.get(i).get(j));
}
}
return result;
}
In your method then just create a new List<List<Integer>> like this and iterate over this new list of lists:
List<List<Integer>> myListTraversed = traverse(myList);
I have some problem with my Java code. I'm supposed to use loops and not any other method.
Say that my ArrayList contains of
[Dog Cat Dog Dog Cat Dog Horse]
My goal is also to remove the copies of Dog and Cat so my final results equals
[Dog Cat Horse]
public void removeDouble(){
int counter = 0;
for (int i = 0 ; i < animals.size(); i++) {
for (int j = 1+i; j < animals.size() ; j++)
//don't start on the same word or you'll eliminate it.
if ( animals.get(j).equals( animals.get(i) ) ) {
animals.remove(animals.get(j));
counter++;
}
}
}
It feels like the "logic" is correct but my code does not work very well. Can somebody help me a little?
You can do like this.
ArrayList<String>list=new ArrayList<>();
list.add("A");
list.add("B");
list.add("C");
list.add("A");
System.out.println("Before "+list); // output[A,B,C,A]
Set<String> listWithoutDuplicates = new LinkedHashSet<String>(list);
list.clear();
list.addAll(listWithoutDuplicates);
System.out.println("list without duplicates : " + list);// output[A,B,C]
The logic for the inner loop is incorrect.
You will skip items every time you have the same item appear consecutively in the list.
Say you had "dog", "dog", "dog", "cat". When you remove the "dog" at index 1, the list now becomes "dog", "dog", "cat".
The problem is that your "j" index is now incremented to 2 so the next test will access the "cat" item, not the "dog" item. So every time you remove an item you are skipping the next item in the list which is why you get inconsistent results.
The solution is to either:
decrement the j variable every time you remove an item
start the inner loop from the end of the list and count down backwards toward 0.
It would be simpler to start from the end of the list and decrement the counter. After removing the double at i, we can break without checking the whole string, because further doubles will be detected when i reaches j.
for(int i=animals.size()-1; i>0; i--) {
for(int j=i-1; j>=0; j--) {
if(animals.get(i).equals(animals.get(j))) {
animals.remove(i);
break;
}
}
}
Moving backwards avoids the problem as you move forward the indexes have changed because you removed earlier elements (and you failed to adjust the index to take that into account).
Another problem with your logic you were using remove(object) rather than remove(index), which causes the first matching object to be removed. However, based on expected output, you want to preserve the order of the first matching objects. So instead you should have removed the last matching object, via index.
If you want to move forward rather than backwards, but you don't wish to make adjustments to the index after a removal, it is possible to make use of iterator's remove method:
for(int i=0; i<animals.size()-1; i++) {
ListIterator<?> iter = animals.listIterator(i+1);
while(iter.hasNext()) {
if(animals.get(i).equals(iter.next())) {
iter.remove();
}
}
}
Unfortunately the outer loop here cannot use an iterator because that would result in a ConcurrentModificationException.
Finally, you could also use a subList to solve it with a single explicit loop:
for(int i=0; i<animals.size()-1; i++) {
animals.subList(i+1, animals.size()).removeIf(animals.get(i)::equals);
}
In Java 8 we can use Stream API to remove duplicates, Like below snippet.
List<String> uniqueAnimal = animal.stream().distinct().collect(Collectors.toList());
Working Example.
import java.util.*;
import java.util.stream.Collectors;
public class MyClass {
public static void main(String args[]) {
List<String> animal = new ArrayList<>();
animal.add("Dog");
animal.add("Cat");
animal.add("Dog");
animal.add("Dog");
animal.add("Cat");
animal.add("Dog");
animal.add("Horse");
List<String> uniqueAnimal = animal.stream().distinct().collect(Collectors.toList());
System.out.println("animal => " + animal);
System.out.println("uniqueAnimal => " + uniqueAnimal);
}
}
With Java 8 stream you can do as follows:
public class RemoveDuplicates {
public static void main(String[] args) {
removeDuplicateElements(Arrays.asList("Dog","Cat","Dog","Dog","Cat","Dog","Horse"));
}
private static void removeDuplicateElements(List<String> animalList)
{
animalList.stream().distinct().collect(Collectors.toList()).forEach(System.out::println);
}
}
Your removing the items as you are iterating over them, have an array that holds indexes, and when you find a double, add the index to the indexes array. Iterate over the indexes array and delete from the animals arraylist.
Your current code -
for (int i = 0; i < animals.size(); i++) {
for (int j = 1 + i; j < animals.size(); j++)
if (animals.get(j).equals(animals.get(i))) {
animals.remove(animals.get(j)); // this would remove the current element only if the previous element is same as the current element
// since the index `j` would change post that
}
}
}
A simple way to do this is
animals.stream().distinct().collect(Collectors.toList()).forEach(System.out::print);
Or using -
Set<String> distAnimal = new HashSet<>(animals);
System.out.println(Arrays.toString(distAnimal.toArray()));
Thanks for all the answers. I still have a few problems, this is what i have came up with:
int counter =0;
for(int i = 0 ; i < animals.size() ; i++){
for(int j = animals.size() -1 ; j>i ; j--){
if(animals.get(j).equals(animals.get(i))){
counter++;
}
}
}
System.out.println(counter);
}
So now I'm starting the inner loop from the end of the ArrayList. Priority right now is only the get the loop working and then add remove etc.
Cheers!
I am doing a simple Java program and I need to remove all of the contiguous duplicates in a String ArrayList.
My String ArrayList is something like this:
list = [a,b,c,c,d,a,b,c,d]
My goal is removing all (and only!) the contiguous duplicates so that the result would be: [a,b,c,d,a,b,c,d]. As you can see, one of the two contiguous "c" has been removed.
I tried something like this:
for (int i = 0; i<list.size(); i++) {
if (list.get(i).compareTo(list.get(i+1))==0) {
positionToRemove.add(i);
}
}
Where positionToRemove will at the end contain all the position of the contiguous elements which I will then remove using list.remove() (still not done)
Unfortunately I get
java.lang.IndexOutOfBoundsException
I am quite positive there is a very simple way to achieve this but I can't remember it at the moment!
There is no need to store the indexes of the elements you need to remove. Just remove it directly by:
int size = list.size();
for (int i = size - 1; i >= 1; i--) {
if (list.get(i).compareTo(list.get(i - 1)) == 0) {
list.remove(i);
}
}
In the last iteration of the for loop, list.get(i+1) goes beyond the bounds of the list and thus the IndexOutOfBoundsException. In any array/arraylist, the maximum accessible index is always size/length - 1.
To fix that you need to change your logic a bit.
for (int i = 1; i<list.size(); i++) {
if (list.get(i-1).compareTo(list.get(i))==0) {
positionToRemove.add(i);
}
}
When you access the List using index + 1 or i+1, you overstep the bounds of the List on the last iteration. You can fix this by setting the conditional for your for loop to i < list.size() -1.
for (int i = 0; i < list.size() -1; i++) {
if (list.get(i).compareTo(list.get(i+1))==0) {
positionToRemove.add(i);
}
}
It should not reach the length of your list. You must shutdown the traverses at size -1.
for (int i = 0; i<list.size() - 1; i++) {
if (list.get(i).compareTo(list.get(i+1))==0) {
positionToRemove.add(i);
}
}
Where positionToRemove will at the end contain all the position of the
contiguous elements which I will then remove using list.remove()
(still not done)
Instead of storing each position, you could start from the end of the list and directly remove the current element if it's the same as its left neighbour. Using this, you don't need to create another list containing the indexes of the objects you want to remove.
List<String> list = new ArrayList<>(Arrays.asList("a","b","c","c","d","a","b","c","d"));
for(int i = list.size() - 1; i > 0; i--){
if(list.get(i).compareTo(list.get(i-1)) == 0){
list.remove(i);
}
}
System.out.println(list);
Which outputs:
[a, b, c, d, a, b, c, d]
You can do this with Java 7, using iterator.
Iterator<Integer> iterator = collection.values().iterator();
Integer previousValue = null;
while(iterator.hasNext()) {
Integer currentValue = iterator.next();
if(currentValue.equals(previousValue)){
iterator.remove();
}
previousValue = currentValue;
}
I need to merge two lists into one, in ascending order, not duplicates, and I think my code is really close, I'm just missing something and I can't figure it out. As of now, my code is not working properly in my merge method. I think it has something to do with my loops, but I just can't work around it. My current method prints the new list, but it is not in perfect increasing order. I would appreciate any assistance in figuring out how to make this method print my merged list with ascending order using the contents of l1 and l2.
**Note: I cannot use any built-in array sorting methods.
Thanks!
import java.util.ArrayList;
import java.util.Random;
public class MergeLists {
public static ArrayList<Integer> merge(ArrayList<Integer> l1, ArrayList<Integer> l2){
ArrayList<Integer> mergedList = new ArrayList();
for (int j = 0; j < l1.size(); j++) {
if (l1.get(j) < l2.get(j)) {
mergedList.add(l1.get(j));
mergedList.add(l2.get(j));
} else {
mergedList.add(l2.get(j));
mergedList.add(l1.get(j));
}
}
for (int i = l2.size() - l1.size(); i < l2.size(); i++) {
mergedList.add(l2.get(i));
}
return mergedList;
}
public static ArrayList<Integer> makeRandomIncreasingList(int length) {
ArrayList<Integer> randomList = new ArrayList();
Random rand = new Random();
int inList = rand.nextInt(9) + 1;
int inList2 = rand.nextInt(9) + 1;
for (int i = 0; i < length; i++) {
randomList.add(inList);
inList = inList + inList2;
}
return randomList;
}
public static void doMergeTest() {
ArrayList<Integer> list1 = makeRandomIncreasingList(10);
ArrayList<Integer> list2 = makeRandomIncreasingList(20);
ArrayList<Integer> mergedList = merge(list1, list2);
System.out.println("List 1:" + list1);
System.out.println("List 2:" + list2);
System.out.println("Merged list:" + mergedList);
}
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
System.out.println("Performing merge test #" + (i + 1) + ":");
doMergeTest();
}
}
}
Remove duplicates
arrayList1.remove(arrayList2);
Then merge two arrayList:
arrayList1.addAll(arrayList2);
And Lastly sort the last
collections.sort(arrayList1);
Another way is to use SET: Set doesnt allow duplicates
(HashSet is faster depending on the List implementation class)
Set setmerge = new HashSet(list1);
setmerge.addAll(list2);
list1.clear();
list1.addAll(setmerge);
The first part of your merge() method seems ok, if you modify it a little bit. You need to be going through both lists in parallel, something like
int i = 0, j = 0;
for (; i < l1.size() && j < l2.size();)
And compare individual items and increment indices independently, as in
if (l1.get(i) < l2.get(j)) {
...
i++;
} else
...
j++;
}
The way you were doing it you were literally going in parallel, which is not always correct (think of lists [1 2 2] and [1 1 1] => your merge would look like [1 1 1 2 1 2])
Then, after your "parallel" for-loop (the one where you're iterating through both lists), one of your indices is always going to break your loop because it's at the end of its list. For in-order merging, I usually declare i, j outside the loop (you'll need then after your first for-loop, like above) and then do something like (in your notation):
for (int i1 = i; i1 < l1.size(); i1++) {
mergeList.add(l1.get(i1));
}
for (int i2 = j; i2 < l2.size(); i2++) {
mergeList.add(l2.get(i2));
}
After your first for-loop, you get to the end of exactly one of the lists (someone's going to break the loop), so exactly one of the above loops is going to get executed, and that will contain the remaining items, in order.
Edit: your last for-loop of the merge() method is not correct for your purpose.
You have assumed l2 items are always bigger than l1 items, since you are adding remainder of l2 items in the end of the list. You need to compare them with mergedList items and add them accordingly.
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))