removing elements from an array list - java

consider I have an array list like : [2,5,1,8,6]
and I want to remove all elements from 1 till the end .and the arraylist will be like :[2,5]
how can i do this?
thanks

It is worth noting that you cannot add/remove from an Arrays.asList(), but you can do.
List<Integer> list = Arrays.asList(2, 5, 1, 8, 6);
int idx = list.indexOf(1);
if (idx>=0) list = list.subList(0, idx);

List<Integer> list = Arrays.asList(2, 5, 1, 8, 6);
boolean remove = false;
Iterator<Integer> it = list.iterator();
while (it.hasNext() {
if (!remove && it.next() == 1) {
remove = true;
}
if (remove) {
it.remove();
}
}

list = list.subList(0, 1);

The most efficient way to remove elements from ArrayList is to remove them from the end of the list. Each element you remove from the middle of the list will result in all the latter elements being moved to the left. If the list is large, this can result in a significant performance issue.
However, in your case, you might be better off just creating a new sublist with the remaining two elements.

Another way of doing it would be to simply pop items off the end of the List until we have popped the starting element. Each item can be popped in O(1) time, so the entire operation is O(n).
class Main{
private static List<Integer> inputs = new ArrayList<Integer>();
public static void main(String args[]){
for (int x: new int[]{2,5,1,8,6})
inputs.add(x);
System.out.println(inputs);
int start=inputs.indexOf(1);
if (start>=0){ //check if there is a 1 in input
while (inputs.size()>start)
inputs.remove(inputs.size()-1);
}
System.out.println(inputs);
}
}

Related

Finding multiple min/max using Collections.min/max

In an example I was working on, I was trying to find the smallest three elements in a list (without sorting the list) and then add those three elements into a new list.
Because it was an example I could just simple use a for loop, use Collections.min(list) add that element to the new list, then remove that element from the original list. If I had not removed the element, I would get the same element three times. However, by removing the element, I got my desired outcome.
How can I do this without removing the max/min elements from the list?
If you want to find the max/min 3 elements, I would suggest you to use a PriorityQueue:
PriorityQueue<Integer> pq = new PriorityQueue<>(k);
And then in a loop, add elements to this queue.
And then you can add these 3 elements to the list by removing from the queue and simply return from the method.
Even better would be to use 3 seperate variables and directly loop on the main list. Note: this method will not be feasible if you later on update 3 to some other value. Whereas PriorityQueue approach will be flexible.
public static void main (String[] args) throws java.lang.Exception {
Integer arr[] = {2, 6, 5, 3, 7, 9, 12, 35, 1, 3};
List<Integer> incoming = Arrays.asList(arr);
Comparator<Integer> maxFirstComparator = (x, y) -> Integer.compare(y,x);
printList(getMinOrMaxKNumbers(incoming, 3, null));
System.out.println();
printList(getMinOrMaxKNumbers(incoming, 3, maxFirstComparator));
}
/*
* gets the max/min K elements from the List
* #param comparator if null is passed the method uses natural ordering
*
*/
private static List<Integer> getMinOrMaxKNumbers(List<Integer> incoming, int k, Comparator<Integer> comparator) {
int n = incoming.size();
PriorityQueue<Integer> pq = comparator == null ? new PriorityQueue<>(n) : new PriorityQueue<>(n, comparator);
for (int i : incoming) {
pq.add(i);
}
List<Integer> outgoing = new ArrayList<>(k);
for (int i = 0; i < k; i++) {
outgoing.add(pq.poll());
}
return outgoing;
}
private static void printList(List<Integer> list) {
list.stream().forEach(x -> System.out.print(x + " "));
}
I don't think there is any straight forward way to do this using the standard library.
The following code contains a utility method to get the set of a number of maximal elements.
It works by keeping the maximal elements in a TreeSet, to which an element is inserted only if it belongs to the maximal elements. A tree set is a good fit here because it is fast to find the minimal element, and to test if an element is contained in the set.
In this way you get good performance, and can be flexible with the number of maximal elements you want.
public class MultipleMaxElements {
public static void main(String[] args) {
List<Integer> l = List.of(4, 2, 5, 8, 2, 8, 0, 1);
System.out.println(maxElements(l, 3, Comparator.naturalOrder()));
System.out.println(maxElements(l, 3, Comparator.<Integer>naturalOrder().reversed()));
}
public static <T> Set<T> maxElements(Iterable<T> list, int nrElems, Comparator<T> cmp) {
TreeSet<T> maxSet = new TreeSet<>(cmp);
for (T elem : list) {
if (maxSet.size() < nrElems) {
maxSet.add(elem);
} else if (!maxSet.contains(elem) && cmp.compare(elem, maxSet.first()) > 0) {
maxSet.pollFirst();
maxSet.add(elem);
}
}
return maxSet;
}
}
In the question text you don't write anything about how duplicate elements in the input list should be handled. This method returns maximal unique elements.
If duplicates should be preserved then a tree based Guava multi-set could be used instead of a normal TreeSet.

Shuffle list except for certain sequences

I want to shuffle an ArrayList but based on some custom conditions:
if my array list was something like [1, 4, 5, 6, 9, 45, 67],
I want to shuffle it but make sure 5, 6, 9 always appear together.
Is there any method available in Collections class to do this?
I have tried doing this, but it throws ConcurrentModificationException
List<Integer> y= new ArrayList<>();
y.add(1);
y.add(4);
y.add(5);
y.add(6);
y.add(9);
y.add(45);
y.add(67);
List<Integer> z = y.subList(2, 5);
y.removeAll(z);
Collections.shuffle(y);
int index = ThreadLocalRandom.current()
.nextInt(0, y.size() + 1);
y.addAll(index,z);
It sounds like your data should really be a list of lists, especially since its likely that you will have more than 1 group that needs to stay together.
You can always flatten it when you need.
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public class Example {
public static void main(String[] args) {
List<List<Integer>> y = new ArrayList<List<Integer>>();
y.add(new ArrayList<Integer>(Arrays.asList(1)));
y.add(new ArrayList<Integer>(Arrays.asList(4)));
y.add(new ArrayList<Integer>(Arrays.asList(5, 6, 9)));
y.add(new ArrayList<Integer>(Arrays.asList(45)));
y.add(new ArrayList<Integer>(Arrays.asList(67)));
Collections.shuffle(y);
List<Integer> flatList = new ArrayList<>();
y.forEach(flatList::addAll);
}
}
A simple way of doing this is to store your target elements in a separate List:
List<Integer> target = new ArrayList<>();
target.add(5);
target.add(6);
target.add(9);
Then shuffle your main list:
Collections.shuffle(y);
Then get a random number from 0 -> y.size().
Random ran = new Random();
int pos = ran.nextInt(y.size());
And insert your target list into your original list:
y.addAll(pos, target);
Note: this assumes your original list has the target 3 numbers removed already.
Without seeing your code, I'd think that the ConcurrentModificationExceptions are thrown because you try to remove the group elements from the list or to add them back in while iterating it. Changing a collection while iterating it leads to those exceptions: Iterating through a Collection, avoiding ConcurrentModificationException when removing in loop.
It will get a lot easier if you do not treat the groups as the exception, but as the norm. What I mean by this is that you should convert your List<?> into a List<List<?>> where each sub list contains either one element or one of the groups. You can then shuffle that list easily with Collections.shuffle() and flatten it again.
Look at this rough implementation:
List<Integer> ints = new ArrayList<>(asList(2, 3, 5, 4, 8, 7, 11, 55));
List<List<Integer>> groups = asList(asList(5, 4), asList(7, 11));
// remove all the grouped elements from the list
groups.forEach(ints::removeAll);
// wrap the single elements into list and join them with the groups
List<List<Integer>> wrapped = Stream.concat(ints.stream().map(Arrays::asList),
groups.stream())
.collect(Collectors.toList());
Collections.shuffle(wrapped);
// flatten the list into single elements again
List<Integer> shuffled = wrapped.stream()
.flatMap(Collection::stream)
.collect(Collectors.toList());
System.out.println(shuffled); // e.g. [55, 3, 7, 11, 2, 8, 5, 4]
// ----- ----
Note that while this is quite readable, it is probably not the most efficient or error proof solution. But it should give you an idea how to tackle the problem.
Edit after comment from Gonen I. Here is a helper method to only remove the exact sequences and not random parts of them all over the list:
private static <T> void removeSequence(List<T> list, List<T> sequence)
{
int indexOfSubList = Collections.lastIndexOfSubList(list, sequence);
while (indexOfSubList != -1)
{
for (int j = 0; j < sequence.size(); j++)
{
list.remove(indexOfSubList);
}
indexOfSubList = Collections.lastIndexOfSubList(list, sequence);
}
}
Use it by replacing groups.forEach(ints::removeAll); by groups.forEach(group -> removeSequence(ints, group));

Finding the Intersection of 2 sorted lists

I have an assignment for
Given two sorted lists of comparable items,
L1 and L2. You can assume that in L1 and
L2 all elements are different (no duplicates) but t
he interception between L1 and L2 may be
non-empty.
(b)
Implement an efficient method in
Java to compute the symmetric difference(∆)
between L1 and L2, L1 ∆L2. Please remember that in
set theory, the symmetric
difference of two sets A and B is the set of elements either in A or in B but not in both.
Example: Suppose A = {1,3,5,7,9} and B = {1,2,3,4,5}, A ∆ B = {2,4,7,9}.
I wrote this so far but I don't know why it stops the search at the end of the first list and doesn't continue checking the 2nd list for differences. Any help?
public static <AnyType extends Comparable<? super AnyType>>
void symDifference(List<AnyType> L1, List<AnyType> L2,
List<AnyType> Difference)
{
ListIterator<AnyType> iterL1 = L1.listIterator();
ListIterator<AnyType> iterL2 = L2.listIterator();
AnyType itemL1 = null;
AnyType itemL2 = null;
if (iterL1.hasNext() && iterL2.hasNext())
{
itemL1 = iterL1.next();
itemL2 = iterL2.next();
}
while (itemL1 != null && itemL2 != null)
{
int compareResult = itemL1.compareTo(itemL2);
if (compareResult == 0)
{
itemL1 = iterL1.hasNext() ? iterL1.next() : null;
itemL2 = iterL2.hasNext() ? iterL2.next() : null;
}
else if (compareResult < 0)
{
Difference.add(itemL1);
itemL1 = iterL1.hasNext() ? iterL1.next() : null;
}
else
{
Difference.add(itemL2);
itemL2 = iterL2.hasNext() ? iterL2.next() : null;
}
}
}
public static void main(String[] args)
{
LinkedList<Integer> list1 = new LinkedList<>();
LinkedList<Integer> list2 = new LinkedList<>();
LinkedList<Integer> difList = new LinkedList<>();
list1.add(1);
list1.add(3);
list1.add(5);
list1.add(7);
list1.add(9);
list2.add(1);
list2.add(2);
list2.add(3);
list2.add(4);
list2.add(5);
symDifference(list1,list2,difList);
System.out.println(difList);
}
}
Well, think about this.
list1 {1, 2, 3, 5}
list2 {1, 5}.
As shmosel said, what happen if your loop runs twice? It exit the loop, and the function.
Ideally, you want to go through all elements on both array.
BTW, I don't think your solution is working as well (you can of cause, but your code will look super ugly, probably takes O(list1.length * list2.length)). Since both lists are sorted, you can compare both element, and loop the smaller element list first. For example, using list1 and list2, compare 1 and 1, both equal, then move to 2 and 5. Then compare 2 and 5, add 2 to the list, and move 2 to 3 ONLY. Which takes O(list1.length + list2.length).
It’s a classic pitfall. When one list runs dry, your loop stops (as it should). At this point you will still want to exhaust the other list. So after your while loop insert the logic to copy the remaining elements from the other list. Since you know one list is done and only one has elements remaining, but you don’t know which, the easy solution is just to take the remaining elements from both lists. Since both lists were sorted, you know that the remainder of the list that still has elements in it cannot contain any elements from the run-dry list, so you simply add them all to your result. All in all you will probably add two while loops after the loop you have, one for iterL1 and one for iterL2. Since each of these run in linear time, your time complexity will not get hurt.

Combining ArrayList without duplicates

import java.util.ArrayList;
import java.util.Collections;
public class SmartCombining {
public static void main(String[] args) {
ArrayList<Integer> list1 = new ArrayList<Integer>();
ArrayList<Integer> list2 = new ArrayList<Integer>();
Collections.addAll(list1, 4, 3);
Collections.addAll(list2, 5, 10, 4, 3, 7);
smartCombine(list1, list2);
System.out.println(list1);
System.out.println(list2);
}
public static void smartCombine(ArrayList<Integer> first,
ArrayList<Integer> second) {
first.addAll(second);
}
}
So, I want to combine two lists into one, but if the second list contains a number from the first it won't be added. So far my method adds them all together.
Well, one way to do it is to iterate through the second list while checking if each element exists in the first list. If it doesn't, add it.
public static void smartCombine(ArrayList<Integer> first, ArrayList<Integer> second) {
for(Integer num : second) { // iterate through the second list
if(!first.contains(num)) { // if first list doesn't contain current element
first.add(num); // add it to the first list
}
}
}
Another way would be for you to hold your values inside a set (like HashSet) which doesn't allow any duplicates. Then you can combine them like:
first.addAll(second);
One more way you could do it is to first remove all elements from the first list that exist in the second list (the ones that would be duplicated). Then you add all elements of the second list to the first list.
public static void smartCombine(ArrayList<Integer> first, ArrayList<Integer> second) {
first.removeAll(second); // remove elements that would be duplicated
first.addAll(second); // add elements from second list
}
The simple, no brains solution:
Set<Integer> joinedSet = new HashSet<Integer>();
joinedSet.addAll(list1);
joinedSet.addAll(list2);
Remove duplicates, then merge both lists:
list1.remove(list2);
list1.addAll(list2);
If you dont want to alter the original list, then first create a backup:
list1BP = new ArrayList(list1);
Another approach is to use HashSet, see other answers.
Use Set, it has been created for that purpose. A Set cannot contain 2 identical elements, based on the equals method.
Set<Integer> list1 = new HashSet<Integer>();
Set<Integer> list2 = new HashSet<Integer>();
Using a combination of ArrayList and contains method is an antipattern here.
There are two easy way you can combine two Lists and duplicate will be removed.
1) First and very easiest way you can get your output, by creating equivalent HashSet object of your ArrayList. Since HashSet does not allow duplicates.
public static void main(String[] args) {
ArrayList<Integer> list1 = new ArrayList<Integer>();
ArrayList<Integer> list2 = new ArrayList<Integer>();
Collections.addAll(list1, 4, 3);
Collections.addAll(list2, 5, 10, 4, 3, 7);
System.out.println(smartCombine(list1, list2));
}
public static HashSet<Integer> smartCombine(ArrayList<Integer> first, ArrayList<Integer> second) {
first.addAll(second);
HashSet<Integer> hs = new HashSet<Integer>(first);
return hs;
2) There is another way using advanced for loop. Iterate the second list and check if the current element is not in first list and then add the current element.
public static void main(String[] args) {
ArrayList<Integer> list1 = new ArrayList<Integer>();
ArrayList<Integer> list2 = new ArrayList<Integer>();
Collections.addAll(list1, 4, 3);
Collections.addAll(list2, 5, 10, 4, 3, 7);
smartCombine(list1, list2);
System.out.println(list1);
}
public static void smartCombine(ArrayList<Integer> first, ArrayList<Integer> second) {
for (Integer num : second) {
if (!first.contains(num)) {
first.add(num);
}
}
}
Note: The second way will work fine only if first list has no duplicates.
Have you tried ArrayList.addAll()
Look at this java doc
As pointer out this would not handle duplicates which can easily be removed using a Set
use contains(Object) method in ArrayList
public static void smartCombine(ArrayList<Integer> first,
ArrayList<Integer> second) {
for(Integer i :second){
if(!first.contains(i)) { // if first list doesn't contain this item, add item to the first list.
first.add(i);
}
}
}

Trying to find all occurrences of an object in Arraylist, in java

I have an ArrayList in Java, and I need to find all occurrences of a specific object in it.
The method ArrayList.indexOf(Object) just finds one occurrence, so it seems that I need something else.
I don't think you need to be too fancy about it. The following should work fine:
static <T> List<Integer> indexOfAll(T obj, List<T> list) {
final List<Integer> indexList = new ArrayList<>();
for (int i = 0; i < list.size(); i++) {
if (obj.equals(list.get(i))) {
indexList.add(i);
}
}
return indexList;
}
I suppose you need to get all indices of the ArrayList where the object on that slot is the same as the given object.
The following method might do what you want it to do:
public static <T> int[] indexOfMultiple(List<T> list, T object) {
List<Integer> indices = new ArrayList<>();
for (int i = 0; i < list.size(); i++) {
if (list.get(i).equals(object)) {
indices.add(i);
}
}
// ArrayList<Integer> to int[] conversion
int[] result = new int[indices.size()];
for (int i = 0; i < indices.size(); i++) {
result[i] = indices.get(i);
}
return result;
}
It searches for the object using the equals method, and saves the current array index to the list with indices. You're referring to indexOf in your question, which uses the equals method to test for equality, as said in the Java documentation:
Searches for the first occurence of the given argument, testing for equality using the equals method.
Update
Using Java 8 streams it'll become much easier:
public static <T> int[] indexOfMultiple(List<T> list, T object) {
return IntStream.range(0, list.size())
.filter(i -> Objects.equals(object, list.get(i)))
.toArray();
}
This is similar to this answer, just uses stream API instead.
List<String> words = Arrays.asList("lorem","ipsum","lorem","amet","lorem");
String str = "lorem";
List<Integer> allIndexes =
IntStream.range(0, words.size()).boxed()
.filter(i -> words.get(i).equals(str))
.collect(Collectors.toList());
System.out.println(allIndexes); // [0,2,4]
iterate over all elements, don't break the loop
each element of the ArrayList compare with your object ( arrayList.get(i).equals(yourObject) )
if match than the index ( i ) should be stored into a separate ArrayList ( arraListMatchingIndexes).
Sometimes in this way I do a "remove all", when I need the positions too.
I hope it helps!
Do
for (int i=0; i<arrList.size(); i++){
if (arrList.get(i).equals(obj)){
// It's an occurance, add to another list
}
}
Hope this helps.
Java 8+
If you want to precompute the indexes of every value in the List, Collectors.groupingBy can be used on an IntStream of indexes.
import java.util.stream.Collectors;
import java.util.stream.IntStream;
//...
List<Integer> list = Arrays.asList(1, 2, 2, 1, 4, 5, 4, 3, 4, 5, 0);
final Map<Integer, List<Integer>> indexMap = IntStream.range(0, list.size()).boxed()
.collect(Collectors.groupingBy(list::get));
//Map of item value to List of indexes at which it occurs in the original List
Then, to find all the indexes of a specific value, use get on the Map in constant time.
List<Integer> indexes = indexMap.get(value);
Demo

Categories

Resources