Java ArrayList search and remove - java

I am attempting to search through an array list to find a value (which may reoccur) and remove all instances of that value. I also would like to remove from a separate array list, values that are at the same location. Both ArrayLists are ArrayList<String>.
For example I am looking for the number 5 in ArrayList2:
ArrayList 1 ArrayList2
cat 1
pig 2
dog 5
chicken 3
wolf 5
Once I find the number 5, in both locations, I would like to remove dog and wolf from ArrayList1. My code has no errors but it doesn't seem to be actually removing what I am asking it.
//searching for
String s="5";
//for the size of the arraylist
for(int p=0; p<ArrayList2.size(); p++){
//if the arraylist has th value of s
if(ArrayList2.get(p).contains(s)){
//get the one to remove
String removethis=ArrayList2.get(p);
String removetoo=ArrayList1.get(p);
//remove them
ArrayList2.remove(removethis);
ArrayList1.remove(removetoo);
}
}
When I print the arrayLists they look largely unchanged. Anyone see what I am doing wrong?

When you are both looping and removing items from an array, the algorithm you wrote is incorrect because it skips the next item following each removal (due to the way in which you increment p). Consider this alternative:
int s = 5;
int idx = 0;
while (idx < ArrayList2.size())
{
if(ArrayList2.get(idx) == s)
{
// Remove item
ArrayList1.remove(idx);
ArrayList2.remove(idx);
}
else
{
++idx;
}
}

If you want to iterate over a collection and remove elements of the same collection, then you'll have to use an Iterator, e.g.:
List<String> names = ....
List<Integer> numbers = ....
int index = 0;
Iterator<String> i = names.iterator();
while (i.hasNext()) {
String s = i.next(); // must be called before you can call i.remove()
if (s.equals("dog"){
i.remove();
numbers.remove(index);
}
index++;
}
EDIT
In your case, you'll have to manually increment a variable to be able to remove items from the other List.

You could use two iterators:
Iterator<String> i1 = arrayList1.iterator();
Iterator<Integer> i2 = arrayList2.iterator();
while (i1.hasNext() && i2.hasNext()) {
i1.next();
if (i2.next() == s) {
i1.remove();
i2.remove();
}
}
Though as has been pointed out yet, it would probably be easier to use a map.

I think the contains method compares the two objects. However, the object "s" is different from the object in the ArrayList. You should use typed arrays (i.e. ArrayList) and make sure to compare values of each objects, not the objects themselves ...

You should declare your list as follows -
List<String> list1 = new ArrayList<String>();
//...
List<Integer> list2 = new ArrayList<Integer>();
//...
And instead of contains method use equals method.
Also to remove while iterating the lists use Iterator which you can get as follows -
Iterator<String> it1 = list1.iterator();
Iterator<Integer> it2 = list2.iterator();
//...

You might want to check the indexOf() method of ArrayList, but you have to be careful when removing from a list while iterating on it's elements.

Here's a straight forward solution:
List<Integer> origNums = new ArrayList<Integer>(nums);
Iterator<String> animalIter = animals.iterator();
Iterator<Integer> numIter = nums.iterator();
while (animalIter.hasNext()) {
animalIter.next();
// Represents a duplicate?
if (Collections.frequency(origNums, numIter.next()) > 1) {
// Remove current element from both lists.
animalIter.remove();
numIter.remove();
}
}
System.out.println(animals); // [cat, pig, chicken]
System.out.println(nums); // [1, 2, 3]

I agree with Makoto, using Map maybe more beneficial. If you will be searching only using the values of ArrayList2, then you have multiple values for one key.
For example, 5 refers to dog and wolf. For this you can add a list of values to the key - 5.
HashMap aMap = HashMap();
ArrayList key5 = new ArrayList();
key5.add("dog");
key5.add("wolf");
aMap.put(5, key5);
So when you need to remove all values for 5, you do
aMap.remove(5);
And it will remove the list containing dog and wolf.

Related

Arraylist Comparison using one loop

It has been a long since something came to my mind while starting to code and using lists or array lists. When comparing values of one array to every other elements in another array, I used to do it in two for loops since it was the easiest way to do that.but recently I came to know that it increases much time complexity, I thought about another solution.can anyone help me in solving this case using any algorithm. I am using java.but solution in any language would be fine. just the algorithm to do that is needed. Thanks in advance.
This is what i am doing:
a1 = [1,2,3,4,5]
b1 = [9,5,4,3,8,3,7]
I want to check how much time an element in a1 occurs in b1
So what i am doing is:
count = 0;
for(int i = 0;i <a1.length;i++)
{
for(j=0;j<b1.length;j++)
{
if (a1[i] == b1[j])
{
count = count+1;
}
}
}
print("count is" count);
Theres no need of loop to obtain what you want
ArrayList<Integer> l1 = new ArrayList<Integer>();
l1.add(1);
l1.add(2);
l1.add(3);
l1.add(4);
l1.add(5);
ArrayList<Integer> l2 = new ArrayList<Integer>();
l2.add(9);
l2.add(5);
l2.add(4);
l2.add(3);
l2.add(8);
l2.add(3);
l2.add(7);
ArrayList<Integer> lFiltered = new ArrayList<Integer>(l2);
lFiltered.removeAll(l1);
int Times = l2.size() - lFiltered.size();
System.out.println("number of migrants : " + Times);
Suffice it to to generate from l2 a list without elements and l1 and to count elements which have been removed
Use hashing, e.g. using a Set or Map
If you want to compare the objects as a whole:
properly implement equals and hashcode for your class (if not implemented already)
put all the elements of list A into a Set, then see which elements from list B are in that Set
If you just want to compare objects by some attribute:
define a method that maps the objects to that attribute (or combination of attriutes, e.g. as a List)
create a Map<KeyAttributeType, List<YourClass>> and for each element from list A, add the element to that Map: map.get(getKey(x)).add(x)
for each element from list B, calculate the value of the key function and get the elements it "matches" from the map: matches = map.get(getKey(y))
Given your code, your case seems to be a bit different, though. You have lists or arrays of numbers, so no additional hashing is necessary, and you do not just want to see which items "match", but count all combinations of matching items. For this, you could create a Map<Integer, Long> to count how often each element of the first list appears, and then get the sum of those counts for the elements from the second list.
int[] a1 = {1,2,3,4,5};
int[] b1 = {9,5,4,3,8,3,7};
Map<Integer, Long> counts = IntStream.of(b1).boxed()
.collect(Collectors.groupingBy(x -> x, Collectors.counting()));
System.out.println(counts); // {3=2, 4=1, 5=1, 7=1, 8=1, 9=1}
long total = IntStream.of(a1).mapToLong(x -> counts.getOrDefault(x, 0L)).sum();
System.out.println(total); // 4
Of course, instead of using the Stream API you can just as well use regular loops.
Use ArrayLists.
To compare the content of both arrays:
ArrayList<String> listOne = new ArrayList<>(Arrays.asList(yourArray1);
ArrayList<String> listTwo = new ArrayList<>(Arrays.asList(yourArray);
listOne.retainAll(listTwo);
System.out.println(listOne)
To find missing elements:
listTwo.removeAll(listOne);
System.out.println(listTwo);
To enumerate the Common elements:
//Time complexity is O(n^2)
int count =0;
for (String element : listOne){
for (String element2: listTwo){
if (element.equalsIgnoreCase(elemnt2){
count += 1;
}
}
}

Remove an object from an ArrayList without (implicitly) looping through it

I am looping through a list A to find X. Then, if X has been found, it is stored into list B. After this, I want to delete X from list A. As speed is an important issue for my application, I want to delete X from A without looping through A. This should be possible as I already know the location of X in A (I found its position in the first line). How can I do this?
for(int i = 0; i<n; i++) {
Object X = methodToGetObjectXFromA();
B.add(X);
A.remove(X); // But this part is time consuming, as I unnecessarily loop through A
}
Thanks!
Instead of returning the object from yhe method, you can return its index and then remove by index:
int idx = methodToGetObjectIndexFromA();
Object X = A.remove(idx); // But this part is time consuming, as I unnecessarily loop through A
B.add(X);
However, note that the remove method may be still slow due to potential move of the array elements.
You can use an iterator, and if performance is an issue is better you use a LinkedList for the list you want to remove from:
public static void main(String[] args) {
List<Integer> aList = new LinkedList<>();
List<Integer> bList = new ArrayList<>();
aList.add(1);
aList.add(2);
aList.add(3);
int value;
Iterator<Integer> iter = aList.iterator();
while (iter.hasNext()) {
value = iter.next().intValue();
if (value == 3) {
bList.add(value);
iter.remove();
}
}
System.out.println(aList.toString()); //[1, 2]
System.out.println(bList.toString()); //[3]
}
If you stored all the objects to remove in a second collection, you may use ArrayList#removeAll(Collection)
Removes from this list all of its elements that are contained in the
specified collection.
Parameters:
c collection containing elements to be removed from this list
In this case, just do
A.removeAll(B);
When exiting your loop.
Addition
It calls ArrayList#batchRemove which will use a loop to remove the objects but you do not have to do it yourself.

Java integer ArrayList return elements within a specific range

I am having a java ArrayList of integer
ArrayList <Integer> ageList = new ArrayList <Integer>();
I am having some integer values in this arrayList. I want to create a new ArrayList which has all elements in the above arrayList which passes a condition, like value between 25 and 35. ie if my ageList contains values
{12,234,45,33,28,56,27}
my newList should contain
{33,28,27}
How can I achieve this?
Note: I came to java from objective C background, where I used NSPredicate to easly do such kind of things..Any similiar methods in java?
There is no "filter" facility in the standard API. (There is in Guava and Apache Commons however.) You'll have to create a new list, loop through the original list and manually add the elements in range 25-35 to the new list.
If you have no intention to keep the original list, you could remove the elements out of range using an Iterator and the Iterator.remove method.
If you have no duplicates in your list, you could use a TreeSet in which case you could get all elements in a specific range using headSet / tailSet.
Related question: (possibly even a duplicate actually)
What is the best way to filter a Java Collection?
Well, with Guava you could write:
Iterable<Integer> filtered = Iterables.filter(list, new Predicate<Integer>() {
#Override public boolean apply(Integer value) {
return value >= 25 && value <= 35;
}
});
List<Integer> newList = Lists.newArrayList(filtered);
You may use foreach loop
List<Integer> newList = new ArrayList<Integer>();
for (Integer value : ageList) {
if (value >= 25 && value <= 35) {
newList.add(value);
}
}
Try this:
ArrayList<Integer> newList = new ArrayList<Integer>(ageList);
for (Iterator<Integer> it = newList.iterator(); it.hasNext();) {
int n = it.next();
if (n < 25 || n > 35)
it.remove();
}
No there is no built in functionality in java [AFAIK].
The steps can be:
Loop through ageList.
Check for condition.
If condition is success then add that element to new list or else do nothing.
Sample code:
List<Integer> ageList = new ArrayList<Integer>();
//-- add data in ageList
List<Integer> newList = new ArrayList<Integer>();
for (Integer integer : ageList) {
if(integer >= 25 && integer <= 35)
newList.add(integer);
}
Not possible with the standard JCF. You'll have to iterate.
Consider using Guava. It has such kind of utilities.
http://code.google.com/p/guava-libraries/
Iterate over it and just add the ones that match? It's 3 lines of code... 4 including the new ArrayList declration.

Remove multiple elements from ArrayList

I have a bunch of indexes and I want to remove elements at these indexes from an ArrayList. I can't do a simple sequence of remove()s because the elements are shifted after each removal. How do I solve this?
To remove elements at indexes:
Collections.sort(indexes, Collections.reverseOrder());
for (int i : indexes)
strs.remove(i);
Or, using the Stream API from Java 8:
indexes.sort(Comparator.reverseOrder());
indexes.stream().mapToInt(i -> i).forEach(l::remove);
Sort the indices in descending order and then remove them one by one. If you do that, there's no way a remove will affect any indices that you later want to remove.
How you sort them will depend on the collection you are using to store the indices. If it's a list, you can do this:
List<Integer> indices;
Collections.sort(indices, new Comparator<Integer>() {
public int compare(Integer a, Integer b) {
//todo: handle null
return b.compareTo(a);
}
}
Edit
#aioobe found the helper that I failed to find. Instead of the above, you can use
Collections.sort(indices, Collections.reverseOrder());
I came here for removing elements in specific range (i.e., all elements between 2 indexes), and found this:
list.subList(indexStart, indexEnd).clear()
You can remove the elements starting from the largest index downwards, or if you have references to the objects you wish to remove, you can use the removeAll method.
you might want to use the subList method with the range of index you would like to remove and
then call clear() on it.
(pay attention that the second parameter is exclusive - for example in this case, I pass 2 meaning only index 0 and 1 will be removed.):
public static void main(String[] args) {
ArrayList<String> animals = new ArrayList<String>();
animals.add("cow");
animals.add("dog");
animals.add("chicken");
animals.add("cat");
animals.subList(0, 2).clear();
for(String s : animals)
System.out.println(s);
}
}
the result will be:
chicken
cat
You can remove the indexes in reverse order. If the indexes are in order like 1,2,3 you can do removeRange(1, 3).
I think nanda was the correct answer.
List<T> toRemove = new LinkedList<T>();
for (T t : masterList) {
if (t.shouldRemove()) {
toRemove.add(t);
}
}
masterList.removeAll(toRemove);
You can sort the indices as many said, or you can use an iterator and call remove()
List<String> list = new ArrayList<String>();
list.add("0");
list.add("1");
list.add("2");
list.add("3");
list.add("4");
list.add("5");
list.add("6");
List<Integer> indexes = new ArrayList<Integer>();
indexes.add(2);
indexes.add(5);
indexes.add(3);
int cpt = 0;
Iterator<String> it = list.iterator();
while(it.hasNext()){
it.next();
if(indexes.contains(cpt)){
it.remove();
}
cpt++;
}
it depends what you need, but the sort will be faster in most cases
Use guava! The method you are looking is Iterators.removeAll(Iterator removeFrom, Collection elementsToRemove)
If you have really many elements to remove (and a long list), it may be faster to iterate over the list and add all elements who are not to be removed to a new list, since each remove()-step in a array-list copies all elements after the removed one by one. In this case, if you index list is not already sorted (and you can iterate over it parallel to the main list), you may want to use a HashSet or BitSet or some similar O(1)-access-structure for the contains() check:
/**
* creates a new List containing all elements of {#code original},
* apart from those with an index in {#code indices}.
* Neither the original list nor the indices collection is changed.
* #return a new list containing only the remaining elements.
*/
public <X> List<X> removeElements(List<X> original, Collection<Integer> indices) {
// wrap for faster access.
indices = new HashSet<Integer>(indices);
List<X> output = new ArrayList<X>();
int len = original.size();
for(int i = 0; i < len; i++) {
if(!indices.contains(i)) {
output.add(original.get(i));
}
}
return output;
}
order your list of indexes, like this
if 2,12,9,7,3 order desc to 12,9,7,3,2
and then do this
for(var i = 0; i < indexes.length; i++)
{
source_array.remove(indexes[0]);
}
this should resolve your problem.
If the elements you wish to remove are all grouped together, you can do a subList(start, end).clear() operation.
If the elements you wish to remove are scattered, it may be better to create a new ArrayList, add only the elements you wish to include, and then copy back into the original list.
Edit: I realize now this was not a question of performance but of logic.
If you want to remove positions X to the Size
//a is the ArrayList
a=(ArrayList)a.sublist(0,X-1);
Assuming your indexes array is sorted (eg: 1, 3, 19, 29), you can do this:
for (int i = 0; i < indexes.size(); i++){
originalArray.remove(indexes.get(i) - i);
}
A more efficient method that I guess I have not seen above is creating a new Arraylist and selecting which indices survive by copying them to the new array. And finally reassign the reference.
I ended up here for a similar query and #aioobe's answer helped me figure out the solution.
However, if you are populating the list of indices to delete yourself, might want to consider using this:
indices.add(0, i);
This will eliminate the need for (the costly) reverse-sorting of the list before iterating over it, while removing elements from the main ArrayList.

How do I remove sequential elements from a Java ArrayList?

I'm a relatively new Java programmer and I'm having difficuly removing more than one element from an ArrayList. Ideally I'd like to do something like this:
ArrayList ar1 = new ArrayList();
ar1.add(...)
ar1.add(...)
ar1.add(...)
ar1.add(...)
for (int i = 0; i < 2; i++){
ar1.remove(i);
}
I think iterator might help, but I can't find an example that matches close enough to what I'm trying to do. Any help would be appreciated. Thanks.
Here's what you want to do:
ar1.subList(0, 2).clear();
This creates a sublist view of the first 2 elements of the list and then clears that sublist, removing them from the original list. The subList method exists primarily for this sort of thing... doing operations on a specific range of the list.
You can certainly do that
ArrayList ar1 = new ArrayList();
ar1.add("a");
ar1.add("b");
ar1.add("c");
ar1.add("d");
for (int i = 0; i < 2; i++) {
ar1.remove(i);
}
System.out.println(ar1);
Only pay attention that after you remove first element, other elements shift. Thus, calling
ar1.remove(0);
ar1.remove(1);
will effectively remove first and third elements from the list. This will delete first two elements, though:
ar1.remove(0);
ar1.remove(0);
For indexed removals from a list, you need to count backwards:
for (int i = 1; i >= 0; i--)
otherwise, your first removal shifts the items "above" it in the collection and you don't wind up removing the items you think you are removing.
You can use Collection.removeAll(toRemove) if you have a separate list of objects to remove.
http://download.oracle.com/javase/6/docs/api/java/util/Collection.html
If your collection is indexed based, like ArrayList is, you can call
remove(index)
to remove the element at the index. You can do that in a loop, but beware that removing shifts all the indexes as another answer points out.
If all you want to do is remove the first two elements from the list, then
list.remove(0);
list.remove(0);
should do it.
If you know the indexes of the items you want to remove, you can remove them in reverse order, without worrying about shifting indexes:
ArrayList ar1 = new ArrayList();
ar1.add("a");
ar1.add("b");
ar1.add("c");
ar1.add("d");
int[] indexesToRemove = {0,2,3};
Arrays.sort(indexesToRemove);
for (int i=indexesToRemove.length-1; i>=0; i--) {
ar1.remove(indexesToRemove[i]);
}
You could try this:
List<Whatever> l = new ArrayList<Whatever>();
l.add(someStuff);
Iterator<Whatever> it = l.iterator();
int i = 0;
while (i < 2 && it.hasNext()) {
it.next();
it.remove();
i++;
}
Or, more generally:
List<Whatever> l = new ArrayList<Whatever>();
l.add(someStuff);
Iterator<Whatever> it = l.iterator();
while (it.hasNext()) {
Whatever next = it.next();
if (shouldRemove(next)) {
it.remove();
}
}
EDIT: I guess it depends if you are trying to remove particular indices or particular objects. It also depends on how much logic you need to decide if something should be removed. If you know the indices then remove them in reverse order. If you have a set of Objects to be removed, then use removeAll. If you want to iterate over the list and remove objects that match a predicate then use the above code.

Categories