This question already has answers here:
Trying to find all occurrences of an object in Arraylist, in java
(6 answers)
Closed 3 years ago.
Assumed
ArrayList<Integer> list = Arrays.asList(new Integer[] {1,2,3,4,5,6,1,8,9});
Find second occurence
I want to get the index of the second finding of the (multiple) contained element "1" but list.indexOf(1) will always return 0 (as it's the first finding).
Performance
I want to do this without using loops like for or while.
Since I need it for a game, using loops wouldn't be efficient at all.
EDIT: Is there any way to get "indexOf" some element without iterator ?
You cannot do this without iterating.
indexOf iterates, for example.
public int indexOf(Object o) {
if (o == null) {
for (int i = 0; i < size; i++)
if (elementData[i]==null)
return i;
} else {
for (int i = 0; i < size; i++)
if (o.equals(elementData[i]))
return i;
}
return -1;
}
Same is valid for lastIndexOf.
As you can see no Iterator<Integer> is used at all, if that is what worries you.
And, btw, this isn't a performance concern.
Do you have arrays with millions of elements? If you have, consider changing data structure type.
If you are very much concerned about performance, use a HashMap<Integer, List<Integer>>. Then if your want n'th occurence of an element m, you can do map.get(m).get(n). Your map contains elements and their corresponding indexes.
Once your map is built, the time complexity for your query would be O(1)
Example:
public static void main(String[] args){
int[] a = {1, 2, 1, 3, 4, 1};
Map<Integer, List<Integer>> map = new HashMap<Integer, List<Integer>>();
for(int i = 0; i < a.length; i++){
if(map.containsKey(a[i])){
map.get(a[i]).add(i);
}else{
map.put(a[i], new ArrayList<Integer>());
map.get(a[i]).add(i);
}
}
// second index of 1. Note that index starts from 0.
System.out.println(map.get(1).get(1));
}
Result:
2
list.subList(list.indexOf(1) + 1, list.size()).indexOf(1)
list.indexOf(1, list.indexOf(1) + 1);
The first parameter 1 being the object to be searched.
The second parameter list.indexOf(1) + 1 being the starting index for the search.
public class ArrayTest{
public static void main(String[] args) {
int array[] = {32,3,3,4,5,6,88,98,9,9,9,9,9,9,1,2,3,4,5,6,4,3,7,7,8,8,88,88};
for(int i= 0;i<array.length-1;i++){
for(int j=i+1;j<array.length;j++){
if((array[i])==(array[j]) && (i != j)){
System.out.println("element occuring twice are:" + array[j]);
}
}
}
}
}
this program work fine but when i compile it, it print the values again and again i want to print the duplicate value once for example if 9 is present 5 times in array so it print 9 once and if 5 is present 6 times or more it simply print 5...and so on....this what i want to be done. but this program not behave like that so what am i missing here.
your help would be highly appreciated.
regards!
Sort the array so you can get all the like values together.
public class ArrayTest{
public static void main(String[] args) {
int array[] = {32,3,3,4,5,6,88,98,9,9,9,9,9,9,1,2,3,4,5,6,4,3,7,7,8,8,88,88};
Arrays.sort(array);
for (int a = 0; a < array.length-1; a++) {
boolean duplicate = false;
while (array[a+1] == array[a]) {
a++;
duplicate = true;
}
if (duplicate) System.out.println("Duplicate is " + array[a]);
}
}
}
The problem statement is not clear, but lets assume you can't sort (otherwise the problem greatly simplifies). Lets also assume the space complexity is constrained, and you can't keep a Map, etc, for counting the frequency.
You can use use lookbehind, but this unnecessarily increases the time complexity.
I think a reasonable approach is to reserve the value -1 to indicate that an array position has been processed. As you process the array, you update each active value with -1. For example, if the first element is 32, then you scan the array for any value 32, and replace with -1. The time complexity does not exceed O(n^2).
This leaves the awkcase case where -1 is an actual value. It would be required to do a O(n) scan for -1 prior to the main code.
If the array must be preserved, then clone it prior to processing. The O(n^2) loop is:
for (int i = 0; i < array.length - 1; i++) {
boolean multiple = false;
for (int j = i + 1; j < array.length && array[i] != -1; j++) {
if (array[i] == array[j]) {
multiple = true;
array[j] = -1;
}
}
if (multiple)
System.out.println("element occuring multiple times is:" + array[i]);
}
What you can do, is use a data structure that only contains unique values, Set. In this case we use a HashSet to store all the duplicates. Then you check if the Set contains your value at index i, if it does not then we loop through the array to try and find a duplicate. If the Set contains that number already, we know it's been found before and we skip the second for loop.
int array[] = {32,3,3,4,5,6,88,98,9,9,9,9,9,9,1,2,3,4,5,6,4,3,7,7,8,8,88,88};
HashSet<Integer> duplicates = new HashSet<>();
for(int i= 0;i<array.length-1;i++)
{
if(!duplicates.contains(array[i]))
for(int j=i+1;j<array.length;j++)
{
if((array[i])==(array[j]) && (i != j)){
duplicates.add(array[i]);
break;
}
}
}
System.out.println(duplicates.toString());
Outputs
[3, 4, 5, 6, 7, 88, 8, 9]
I recommend using a Map to determine whether a value has been duplicated.
Values that have occurred more than once would be considered as duplicates.
P.S. For duplicates, using a set abstract data type would be ideal (HashSet would be the implementation of the ADT), since lookup times are O(1) since it uses a hashing algorithm to map values to array indexes. I am using a map here, since we already have a solution using a set. In essence, apart from the data structure used, the logic is almost identical.
For more information on the map data structure, click here.
Instead of writing nested loops, you can just write two for loops, resulting in a solution with linear time complexity.
public void printDuplicates(int[] array) {
Map<Integer, Integer> numberMap = new HashMap<>();
// Loop through array and mark occurring items
for (int i : array) {
// If key exists, it is a duplicate
if (numberMap.containsKey(i)) {
numberMap.put(i, numberMap.get(i) + 1);
} else {
numberMap.put(i, 1);
}
}
for (Integer key : numberMap.keySet()) {
// anything with more than one occurrence is a duplicate
if (numberMap.get(key) > 1) {
System.out.println(key + " is a reoccurring number that occurs " + numberMap.get(key) + " times");
}
}
}
Assuming that the code is added to ArrayTest class, you could all it like this.
public class ArrayTest {
public static void main(String[] args) {
int array[] = {32,3,3,4,5,6,88,98,9,9,9,9,9,9,1,2,3,4,5,6,4,3,7,7,8,8,88,88};
ArrayTest test = new ArrayTest();
test.printDuplicates(array);
}
}
If you want to change the code above to look for numbers that reoccur exactly twice (not more than once), you can change the following code
if (numberMap.get(key) > 1) to if (numberMap.get(key) == 2)
Note: this solution takes O(n) memory, so if memory is an issue, Ian's solution above would be the right approach (using a nested loop).
// print duplicates
StringBuilder sb = new StringBuilder();
int[] arr = {1, 2, 3, 4, 5, 6, 7, 2, 3, 4};
int l = arr.length;
for (int i = 0; i < l; i++)
{
for (int j = i + 1; j < l; j++)
{
if (arr[i] == arr[j])
{
sb.append(arr[i] + " ");
}
}
}
System.out.println(sb);
Sort the array. Look at the one ahead to see if it is duplicate. Also look at one behind to see if this was already counted as duplicate (except when i == 0, do not look back).
import java.util.Arrays;
public class ArrayTest{
public static void main(String[] args) {
int array[] = {32,32,3,3,4,5,6,88,98,9,9,9,9,9,9,1,2,3,4,5,6,4,3,7,7,8,8,88,88};
Arrays.sort(array);
for(int i= 0;i<array.length-1;i++){
if((array[i])==(array[i+1]) && (i == 0 || (array[i]) != (array[i-1]))){
System.out.println("element occuring twice are:" + array[i]);
}
}
}
}
prints:
element occuring twice are:3
element occuring twice are:4
element occuring twice are:5
element occuring twice are:6
element occuring twice are:7
element occuring twice are:8
element occuring twice are:9
element occuring twice are:32
element occuring twice are:88
This question already has answers here:
What is an IndexOutOfRangeException / ArgumentOutOfRangeException and how do I fix it?
(5 answers)
Closed 8 years ago.
I cannot see anything wrong with my code:-
import java.util.ArrayList;
public class Main {
public static void main(String[] args) {
int[] A = new int[] {2, 1, 1, 2, 3, 1};
ArrayList<Integer> foundNumbers = new ArrayList<>();
int distinct = 0;
for(int i = 0; i < A.length-1; i++) {
if(foundNumbers.get(i-1) == null) {
foundNumbers.set((i-1), A[i]);
distinct++;
}
}
System.out.println(distinct);
}
}
I want to check if the value of Array element i has already been assigned to ArrayList element i-1, then increment the distinct variable and print how many distinct values are in the array.
Here's the exception when I change the value of i to 1:-
Exception in thread "main" java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
at java.util.ArrayList.rangeCheck(ArrayList.java:604)
at java.util.ArrayList.get(ArrayList.java:382)
at tdd.Main.main(Main.java:19)
The list is completely empty. You haven't put anything in it, yet you're trying to read elements from it with the foundNumbers.get call, so any index will be out of bounds.
To add unique elements from A to the list, get and set are simply the wrong list methods to call, use contains and add if that's what you want to do:
for (int x : A) {
if (!foundNumbers.contains(x))
foundNumbers.add(x);
}
Here is the same logic as above written in a more verbose fashion that might make it easier to understand what is involved:
for (int i = 0; i < A.length; i++) {
boolean found = false;
for (int j = 0; j < foundNumbers.size(); j++) {
if (A[i] == foundNumbers.get(j)) {
found = true;
break;
}
}
if (!found) {
foundNumbers.add(A[i]);
}
}
You don't need the separate distinct variable, since it is simply foundNumbers.size().
Although this works, a List is not very efficient for eliminating duplicates if the count of elements is large, since every contains call requires another loop through the contents of the list. A Set automatically prevent duplicates and internally structures its contents in a way that makes it efficient to do so:
Set<Integer> distinct = new TreeSet<>();
for (int x : A) distinct.add(x);
System.out.println(distinct); // [1, 2, 3]
for(int i = 0; i < A.length-1; i++) {
if(foundNumbers.get(i-1) == null) {
In the first iteration of that loop, i will be set to zero, so the second line is doing .get(-1).
There are multiple issues:
when i is 0, you try to get i-1=-1th element which is not valid
Even when you fix this, since you dont have elements in list, you will still get IndexOutOfBoundsException, since you havent stored any elements yet and your list is empty.
Your loop should be:
for (int i = 0; i < A.length - 1; i++) {
if (foundNumbers.size() > i && foundNumbers.get(i) == null) {//or better you use contains method of list like foundNumbers.contains(someNumber);
foundNumbers.add(A[i]);
distinct++;
}
}
have following problem. suppose i have an array number[n] , i want search multiple number , for example i want to search 12, 45 ,1 ,6,8,5, and if every number present array then i can get favorable result. so there is one way , i just pick one element like 7
if it is present in array number[n], then can get inside the loop , and again initialize another loop and check that if second number is in the number[n] , and so on, so here i need same number of loop as the number of searching numbers. so is there is another way to deal with such problem. because it will running time will be polynomial.
here is my code:
import java.util.Scanner;
class Number {
boolean check(int[] num)
{
for (int i = 0; i < 5; i++) {
if (num[i] == 7) {
for (j = 0; j < 5; j++) {
if (num[j] == 8) {
for (int k = 0; k < 5; k++) {
if (num[k] == 9) {
return true;
}
else
continue;
}
} else
continue;
}
} else
return false;
}
}
public static void main(string [] args)
{
Number obj1 = new Number();
Scanner input = new Scanner(System.in);
int [] num =new int[5];
for(int i=0;i<5;i++)
num[i] =input.nextInt();
boolean get ;
get = obj1.check(num []);
System.out.print(response);
}
}
You could do something like this.
public static boolean allFoundIn( int[] toSearch, int... numbers )
Set numbersSet = new HashSet(Arrays.asList(numbers));
numbersSet.removeAll(Arrays.asList(toSearch));
return numbersSet.isEmpty();
}
Then in your main, just call
allFoundIn(num, 7, 8, 9);
which will return true if 7, 8 and 9 are all found in the array num.
If you want a sub-polynomial solution then there are a few possibilities.
1) Sort both lists, then loop like so (pseudocode)
toFind = <first element of listToFind>
for i in listToSearch:
if i == toFind:
if toFind is last element of listToFind:
return true
toFind = next element of listToFind
else if i > toFind:
return false
2) Put all the elements of the list to search in a HashSet. Then loop over the elements you want to find and see if it's in the HashSet. If they all are then they're all in the list. If not then they're not all in the list. HashSet has fast lookup, so it will likely be better than polynomial time.
and since I was already beaten to the punch for 2, I'll stop thinking of alternatives and post.
Yes, you can dramatically reduce the number of passes. Firstly though, don't hard code you search numbers like that with a separate loop for each. Create one array to store the numbers being searched for and one containing the numbers being searched. Sort each in the same direction, eg ascending order. Create two ints to act as counters, one for each array. Now use a while loop to compare the numbers in each array at the positions the counters are at.
How you advance the counters depends on how the numbers compare. If the number in the array of ones being searched for is larger than the one being searched, you advance the one being searched. If the other way around you advance the one being searched and if equal you advance both and record the match. Keep going until the end of one array is reached.
Using this method you only traverse the arrays a maximum of one time. I'd write example code but I'm typing on my phone!
This solution is not the fastest since it does a binary search for every number. Additionally, it has to be sorted first. It would be better to put all your source numbers into a hash set, like in David Wallace's solution. Then each search time is constant instead of depending on the size of your source array.
boolean check(int[] num) {
int[] toSearch = new int[] { 12, 45, 1, 6, 8, 5 };
for (int search : toSearch) {
if (Arrays.binarySearch(num, search) == -1) {
return false;
}
}
return true;
}
If you want to use a hash set, you could do it like this:
boolean check(Integer[] num) {
HashSet<Integer> numSet = new HashSet<>(Arrays.asList(num));
int[] toSearch = new int[] { 12, 45, 1, 6, 8, 5 };
for (int search : toSearch) {
if (!numSet.Contains(search)) {
return false;
}
}
return true;
}
This question already has answers here:
Iterating through a Collection, avoiding ConcurrentModificationException when removing objects in a loop
(31 answers)
Closed 10 years ago.
I have array list of strings. I want to check in specific moment if in this array I have more elements than my "i", if yes I want to remove that elements. For example. I have five elements in array. I choose element which index is four. I want to check if exist higher element(in this case that higher will be element which index is 5) and remove that element. If I choose 3 element I want to remove 4 and 5 element. I do something like that:
for(int j = 0; j<descriptions.size();j++){
if(!descriptions.get(i+1).isEmpty()){
descriptions.remove(i+1);
}
}
This solution work good when I choose 3 element and two elements was removed. But when I want choose 4 element I get index out of bound exception. How I can solve my problem?
I don't quite see the point of using for loop in your code.
What you probably want to do is to remove any items beyond i th element in the list.
The easiest way to do is to repeatedly remove the last element from the list.
Here's a sample code for reference:
while(descriptions.size() > i){
descriptions.remove(descriptions.size()-1);
}
public static void main(String[] args) {
//list of string with 5 elements
List<String> descriptions = new ArrayList<String>();
descriptions.add("first");
descriptions.add("second");
descriptions.add("third");
descriptions.add("4");
descriptions.add("5");
//the size you want to check for the list
int i = 3;
int howMuchToRemove = descriptions.size()-i;
//if the list how more object from > i , we will remove objects from it
if (howMuchToRemove > 0)
for (int j=0 ; j < howMuchToRemove ; j++)
//remove the last object in the list
descriptions.remove(descriptions.size()-1);
System.out.println(descriptions.toString());
}
I have five elements in array. I choose element which index is four.
The fifth element is at index 4. if you want to choose the 4th element, it's index will be 3.
Modify your code as following:
int size = descriptions.size();
for(int j = size -1; j>choosenNum; j--)
{
descriptions.remove(j);
}
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<String>();
list.add("a");
list.add("a");
list.add("a");
list.add("a");
list.add("a");
indexToRemove(list, 5);
}
private static void indexToRemove(ArrayList<String> list, int index) {
if (list.size() > index) {
list.remove(index);
System.out.println(index + "th item removed");
} else
System.out.println("Can't remove");
}
You mean a function which will remove the given index element? then try this.
for(int i = descriptions.size()-1; i > indexToDeleteAfter; i--){
descriptions.remove(i);
}
Or, defer to ArrayList:
if(descriptions.size() - 1 > indexToDeleteAfter)
{
descriptions.removeRange(indexToDeleteAfter + 1, descriptions.size() - 1);
}
http://docs.oracle.com/javase/1.4.2/docs/api/java/util/ArrayList.html#removeRange(int,%20int)