I am trying to create a method that removes every Nth element from a List of unknown type (Wildcard), however every way I try doing it, it doesn't remove the specified elements, but I cannot figure out why. I have been struggling with this for two days now, so I am posting here as a last resort. I thank you in advance for any help.
The code I currently have is as follows:
public static void removeEveryNthElement(List<?> list, int n) {
//Set list equal to an ArrayList because List is immutable
list = new ArrayList<>(list);
//If n is negative or zero throw an exception
if(n <= 0) {
throw new IllegalArgumentException("Integer n needs to be a positive number.");
}
//If the list is null, throw an exception
if(list == null) {
throw new NullPointerException("The list must not be null.");
}
//Remove every nth element in the list
for(int i = 0; i < list.size(); i++) {
if(i % n == 0) {
list.remove(i);
}
}
The other way I have attempted is replacing the for loop with the following:
list.removeIf(i -> i % 3 == 0);
However, when I do it like this I receive the error that the % operator is undefined for the argument type.
I have also tried using a for loop to individually add each element from the list into another modifiable list, but no matter what I do, I am having no luck. If you could help me with this it would be greatly appreciated!
The most serious problem with your code is that removing an element at index i changes the index of all following elements and therefore your condition for removing elements (i % n) is wrong after removing the first element.
One way to get around the problem is iterating in reverse order:
for (int i = list.size()-1; i >= 0; i--) {
if (i % n == 0) {
list.remove(i);
}
}
Another way is to increment i not by one, but by n and adjust it for the removed element:
for (int i = 0; i < list.size(); i += n) {
list.remove(i);
i--;
}
and, since i--; followed by i += n; is the same as i += n-1;:
for (int i = 0; i < list.size(); i += n-1) {
list.remove(i);
}
An additional note: the check if (list == null) is useless after the statement list = new ArrayList<>(list);, since new ArrayList<>(list); already throws a NullPointerException if list is null
You need to keep in mind that creating new collection based on other collection is removing references to oryginal collection - values from collection are coppied to new one - any modification will not impact anything that is out of method scope. You'll need to pass the collection that supports deleting an object from itself or return new collection from method. Remember that the type does not define behaviour of object - its depending on the implementation that is compatible with class you cast to. Here is an example of what I said about the backend implementation (both variables are type List but the implementation is different).
Here is code when you want to do this 'in place':
public static void main(String[] args) {
List<Integer> list2 = new ArrayList<>();
list2.add(1);
list2.add(2);
list2.add(3);
list2.add(4);
removeEveryNthElement(list2, 3); // deleted number 3 because it is 3rd element
}
public static void removeEveryNthElement(List<?> list, int n) {
for (int i = 2; i < list.size(); i += 3) {
list.remove(i);
}
}
But I would like to recommend not to do any operation that is not transparent to programmer. It's better to read and understand bigger programms when you know that you pass value to method and 'it does something' then get value back because it got changed. For this example I use generics and streams:
public static void main(String[] args) {
List<Integer> list1 = Arrays.asList(1, 2, 3, 4);
list1 = removeEveryNthElement2(list1, 3); //deleted number 3
System.out.println();
}
public static <T> List<T> removeEveryNthElement2(List<T> list, int n) {
final Predicate<T> p = new Predicate<T>() {
int i = 0;
#Override
public boolean test(final T t) {
return ++i % n != 0;
}
};
return list.stream().filter(p).collect(Collectors.toList());
}
Brandon, let me first suggest that your method is side-effecting the list built in the calling method. This is allowed, but can lead to hard-to-understand bugs in more complicated code. Instead, try making a new list in your method, and assigned the returned value:
public class Remove {
public static void main(String[] args) {
List<String> list = Arrays.asList("a", "b", "c", "d", "e", "f", "g", "h");
list = removeElements(list, 3);
System.out.println(list);
}
public static <T> List<T> removeElements(List<T> list, int n) {
List<T> newList = new ArrayList<T>();
for (int i = 0; i < list.size(); i++) {
if (i % n != 0) {
newList.add(list.get(i));
}
}
return newList;
}
}
As a result, it makes the method simpler, because we're no longer iterating over the list being modified.
Have a look at Side effect--what's this?
to read more about side-effecting.
Related
I am working on a sharding problem.
Imagine I have 10 lists.
Each list has a series of items that are independently sorted.
I want to get the Nth item as if all the lists were sorted together in one large list.
Do I need to sort the lists overall to get an item at a particular index?
I solved a similar but not equivalent problem where there is:
10 lists
Each list represents a range of items that are after the previous list.
here's the code to iterate through all the indexes of the lists:
/* code to iterate through all items in order
* threads refers to one of the lists */
int sizes[] = new int[threads.size()];
for (int i = 0 ; i < threads.size(); i++) {
sizes[i] = threads.get(i).data2.size();
}
int n = 0;
int thread = 0;
int size = threads.size();
int offset = 0;
long iterationStart = System.nanoTime();
while (thread < size) {
// System.out.println(String.format("%d %d", thread, offset + threads.get(thread).data.get(n)));
int current = offset + threads.get(thread).data.get(n);
n = n + 1;
if (n == sizes[thread]) {
offset += sizes[thread];
thread++;
n = 0;
}
}
long iterationEnd = System.nanoTime();
long iterationTime = iterationEnd - iterationStart;
Here's the code to lookup an item by index.
int lookupKey = 329131;
int current = lookupKey;
int currentThread = 0;
int total = 0;
while (current >= 0 && currentThread <= size - 1) {
int next = current - sizes[currentThread];
if (next >= 0) {
total += sizes[currentThread];
current -= sizes[currentThread];
currentThread++;
} else {
break;
}
}
long lookupEnd = System.nanoTime();
long lookupTime = lookupEnd - lookupStart;
System.out.println(String.format("%d %d",
currentThread,
total + threads.get(currentThread).data.get(current)));
I'm hoping there's some property of sorted collections that I can use to retrieve the Nth item in an overall sorted lists.
What I have in effect is multiple partial orders.
I have some other code that does a N way merge between multiple sorted lists. Is the fastest option to run this in a loop up to lookupIndex?
int size1 = threads.size();
int[] positions = new int[size1];
Arrays.fill(positions, 0);
PriorityQueue<Tuple> pq = new PriorityQueue<>(new Comparator<Tuple>() {
#Override
public int compare(Tuple o1, Tuple o2) {
return o1.value.compareTo(o2.value);
}
});
long startOrderedIteration = System.nanoTime();
for (ShardedTotalRandomOrder thread : threads) {
for (int i = 0; i < 10; i++) {
// System.out.println(thread.data2.get(i));
pq.add(thread.data2.get(i));
}
}
List<Integer> overall = new ArrayList<>();
while (!pq.isEmpty()) {
Tuple poll = pq.poll();
ArrayList<Tuple> data2 = threads.get(poll.thread).data2;
if (positions[poll.thread] < data2.size()) {
Tuple nextValue = data2.get(positions[poll.thread]++);
pq.offer(nextValue);
}
overall.add(poll.value);
// System.out.println(String.format("%d %d", poll.thread, poll.value));
}
System.out.println(overall);
long endOrderedIteration = System.nanoTime();
long orderedIterationTime = endOrderedIteration - startOrderedIteration;
You don't need to resort them. Since each list is already sorted you can merge them as follows. This uses a single method to merge two lists based on their relative values. Then it returns that list and feeds it back into the method to merge it with the next list.
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
public class Merging {
public static void main(String[] args) {
List<Integer> list1 = List.of(5,10,15,20,25,30,35,40,45,50);
List<Integer> list2 = List.of(2,4,6,8,10);
List<Integer> list3 = List.of(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20);
int nth = 10;
List<List<Integer>> lists = List.of(list1,list2,list3);
List<Integer> merged = lists.get(0);
for (int i = 1; i < lists.size(); i++) {
merged = mergeLists(merged, lists.get(i));
}
System.out.println(merged.get(nth));
}
prints
7
This works with any type that implements the Comparable interface.
It will loop until one list is exhausted or until both indices exceed the combined list size.
Once either list is finished, the other can be appended via the sublist.
public static <T extends Comparable<? super T>> List<T> mergeLists(List<T> list1, List<T> list2) {
List<T> merged = new ArrayList<>();
int i1 = 0;
int i2 = 0;
while (i1 + i2 < list1.size() + list2.size()) {
if (i1 >= list1.size()) {
merged.addAll(list2.subList(i2,list2.size()));
break;
}
if (i2 >= list2.size()) {
merged.addAll(list1.subList(i1,list1.size()));
break;
}
if(list1.get(i1).compareTo(list2.get(i2)) <= 0) {
merged.add(list1.get(i1++));
} else {
merged.add(list2.get(i2++));
}
}
return merged;
}
}
Here is a relatively efficient (linear with respect to the number of lists) algorithm that leverages some of the power of streams, but avoids a full list merge.
EDIT: To address shortcomings such as array length checking, array destruction, and readability I have improved this example. For better comparison, I have used the same integer test data as the other answer.
This virtual queue backed by the (presumably) immutable array will not mutate or otherwise
public class VirtualQueue<T> {
private List<T> list;
private int index=0;
public VirtualQueue(List<T> list) { this.list = list; }
public boolean hasMore() { return index < list.size(); }
public T pop() { return list.get(index++); }
public T peek() { return list.get(index);}
}
(I suspect that there is an easier way to do this with standard collections)
List<Integer> list1 = List.of(5,10,15,20,25,30,35,40,45,50);
List<Integer> list2 = List.of(2,4,6,8,10);
List<Integer> list3 = List.of(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20);
List<VirtualQueue<Integer>> listList = List.of(
new VirtualQueue<>(list1),
new VirtualQueue<>(list2),
new VirtualQueue<>(list3));
int n=10;
var value = IntStream.range(0,n)
.mapToObj(i -> listList.stream()
.filter(VirtualQueue::hasMore)
.min(Comparator.comparing(l -> l.peek()))
.get().pop())
.skip(n-1).findFirst().get();
//value is now the nth item in a hypothetical merged list.
Assuming that you have k sorted Lists, and you need to obtain the n from the aggregated List (but the merged list itself don't needed), then this problem can be solved in O(n * log k) time, and by using O(k) additional space.
Note:
If the code below looks too much involved, here's the rationale behind that. This solution is more performant than straightforward comparison of elements from each list which can be observed in this and this answers, which time complexity O(n * k) (opposed to O(n * log k)). A moderate additional complexity is a cost of the performance gain, and note that it's still maintainable.
In case you would need to materialize the merged sorted list (solution below is not doing this), you can simply combine the lists together and make use of the built-in Timsort algorithm implementation via List.sort(). Timsort is very good at spotting the sorted runs, therefore sorting a list that consists of sorted chunks would have a linear time complexity.
To address the problem in O(n * log k) time, we can maintain a PriorityQueue which would always have a size of k or less (therefore enqueue/dequeue operation would have a cost of O(log k)). At the beginning, the Queue should be initialized by adding the very first element from each List.
Then we need to perform n iteration (to find the target element). At each iteration step the Head element of the Queue should be removed, and the next element originated from the same list should be added to the Queue (i.e. if let's say the 7th element from the 3rd List appear to be the Head of the Queue, then after removing it, we need to enqueue the 8th element from the 3rd List).
In order to be able to track from which List each element is coming from and what was its index in the List, we can define a custom type:
public class ElementWrapper<V extends Comparable<V>> implements Comparable<ElementWrapper<V>> {
private V value;
private int listIndex;
private int elementIndex;
// all-args constructor, getters
#Override
public int compareTo(ElementWrapper<V> o) {
return value.compareTo(o.getValue());
}
}
And here's how this algorithm for finding the n-th element can be implemented. As I've said, the time complexity is O(n * log k), since we need n iteration step with each step having a cost of O(log k). Additional memory required only to maintain a Queue of k element.
public static <T extends Comparable<T>> T getNElement(List<List<T>> lists, int n) {
Queue<ElementWrapper<T>> queue = initializeWithFirstElements(lists);
T result = null;
int count = 1;
while (!queue.isEmpty()) {
ElementWrapper<T> current = queue.remove();
if (count == n) { // target index was reached
result = current.getValue();
break;
}
count++;
if (hasNext(current, lists)) {
addNext(current, lists, queue);
}
}
return result;
}
public static <T extends Comparable<T>> Queue<ElementWrapper<T>>
initializeWithFirstElements(List<List<T>> lists) {
Queue<ElementWrapper<T>> queue = new PriorityQueue<>();
for (int i = 0; i < lists.size(); i++) {
if (lists.get(i).isEmpty()) continue;
queue.add(new ElementWrapper<>(lists.get(i).get(0), i, 0));
}
return queue;
}
public static <T extends Comparable<T>> boolean
hasNext(ElementWrapper<T> current, List<List<T>> lists) {
return current.getElementIndex() + 1 < lists.get(current.getListIndex()).size();
}
public static <T extends Comparable<T>> void
addNext(ElementWrapper<T> current, List<List<T>> lists,
Queue<ElementWrapper<T>> queue) {
ElementWrapper<T> next = new ElementWrapper<>(
lists.get(current.getListIndex()).get(current.getElementIndex() + 1),
current.getListIndex(),
current.getElementIndex() + 1
);
queue.add(next);
}
Usage example:
public static void main(String[] args) {
List<List<Integer>> input =
List.of(List.of(1, 3), List.of(),
List.of(2, 6, 7), List.of(10), List.of(4, 5, 8, 9)
);
System.out.println(getNElement(input, 1));
System.out.println(getNElement(input, 3));
System.out.println(getNElement(input, 9));
}
Output:
1 // 1st
3 // 3rd
9 // 9th
Note: depending how do you want the n-th element to be indexed the count variable in the getNElement() method should be initialized accordingly, i.e. with 1 if you want to use 1-based indexes, and with 0 if you want n to be 0-based.
i was wondering how can i reorder enum so that all goats are at the beginning and all sheep are at the end of the array. Right now it actually does the trick but until the array size > 100.. The reordering speed also matters so api methods are bit too slow. Any suggestions?
public class Sheep {
enum Animal {sheep, goat};
public static void main (String[] param) {
reorder(Animal.values());
}
public static void reorder (Animal[] animals) {
int l, r, i, j;
i = l = 0; //left most element
r = animals.length - 1;//right most element
int mid = (r+l)/2; // middle element of the array
for(i=0; i < animals.length;i++)
{
if(i < mid)
{
animals[i] = animals[l+1];
System.out.println(animals[r]);
} else if(i >= mid )
{
animals[i] = animals[r-1];
System.out.println(animals[r]);
}
}
}
}
Since an enum implements Comparable, you can simply sort and then reverse the array:
public static void reorder(Animal[] animals) {
Arrays.sort(animals);
for (int i = 0, j = animals.length - 1; i < j; ++i, --j) {
Animal tmp = animals[i];
animals[i] = animals[j];
animals[j] = tmp;
}
}
You might also be able to do it with:
List<Animal> list = Arrays.asList(animals);
Collections.sort(list);
Collections.reverse(list);
This basically does the same thing with API calls with the (very slight) overhead of wrapping the array in a List object. You can even do this:
Arrays.sort(animals, Collections.reverseOrder());
(Thanks to Bhesh Gurung for the idea.)
EDIT: If you have to deal with exactly two values, you can do much better by simply scanning from both ends, swapping as you find two elements out of order:
public static void reorder(Animal[] animals) {
int first = 0;
int last = animals.length - 1;
while (first < last) {
/*
* The unsorted elements are in positions first..last (inclusive).
* Everything before first is the higher animal; everything after
* last is the lower animal.
*/
while (animals[first].ordinal() == 1 && first < last) {
++first;
}
while (animals[last].ordinal() == 0 && first < last) {
--last;
}
if (first < last) {
/*
* At this point, the sort conditions still hold and also we know
* that the animals at first and last are both out of order
*/
Animal temp = animals[first];
animals[first] = animals[last];
animals[last] = temp;
++first;
--last;
}
}
}
However, if all you need to do is generate the right output (and not actually sort the array), then the approach suggested by #ajb in a comment is the best: just count how many sheep and goats there are and print the corresponding values that many times.
If you want to have maximum performance for such a special case you may simply count the number of one of the two possible values and overwrite the array accordingly to get the result that sorting would create:
public static void reorder (Animal[] animals) {
assert Animal.values().length==2;
int numGoat=0;
for(Animal a:animals) if(a==Animal.goat) numGoat++;
Arrays.fill(animals, 0, numGoat, Animal.goat);
Arrays.fill(animals, numGoat, animals.length, Animal.sheep);
}
You can see it as a modified version of counting sort.
I have an arraylist of 50 RANDOM integers. I ask a user to remove a number and all occurences of that number are removed from the list. I did that using
while (randInts.contains(removeInt) )
{
if (randInts.get(i) == removeInt)
randInts.remove(randInts.get(i));
i++;
}
System.out.println("\n" + randInts.toString());
System.out.println("\n" + randInts.size());`
The other part of the problem is to prompt the user to enter another number. The removed number from above is inserted after each occurrence of the second prompted number. I am having issues with the second part as I keep getting IndexOutOfBoundsException.
Use a LinkedList instead; it's a much better choice when you need in-order traversal but not really random access, and when you need to insert and remove elements in the middle of the list.
You can accomplish what you're wanting (removing all instances of removeInt and inserting removeInt after every instance of insertAfterInt) with a simple traversal of the list's iterator:
ListIterator<Integer> li = randInts.listIterator();
while(li.hasNext()) {
int i = li.next();
if(removeInt == i) // assumes removeInt is an int; use equals() for Integer
li.remove();
if(insertAfterInt == i)
li.add(removeInt); // the iterator will skip this element, so it won't get removed
}
I see two big issues: You're not bounding i to anything, and you wrote an n^2 loop (you can do this in linear time).
You're shrinking the size of the `List` as you go...take this simple example:
Say you want to remove all instances of 5
Given a list that looks like {1,2,3,5,5}
When i = 3 you will remove the first 5, making the list look like: {1,2,3,5}
then you will attempt to remove the element at i = 4, but that element you want to remove is really now at i = 3, and you'll get the IndexOutOfBoundsException
You don't want to use a `contains`, as this expands the worst case performance of your loop to n^2, this would be faster:
int size = randInts.size() - 1;
for (int i = size; i >= 0; i--){
if (randInts.get(i).equals(removeInt))
randInts.remove(i);
}
while (randInts.contains(removeInt) )
{
if(i<randInts.size());
{
if (randInts.get(i) == removeInt)
randInts.remove(randInts.get(i));
}//if
i++;
}while
I am guessing you are starting with a collection of 50 items (randInts) and removing the items that users enter (i)?
If that is the case, once your remove an item, your collection then only 49 indexes left and get gets by the index. Try something like...
if (randInts.contains(i)){
randInts.remove(randInts.indexOf(i));
}
This is n^2, but it should work
int i = 0;
while(i < loFnumbers.size()){
if(loFnumbers.get(i) == removeInt){
loFnumbers.remove(i);
continue;
}
i++;
}
Here's an approach that avoids any state mutation (i.e. randInts is never modified):
package so;
import java.util.ArrayList;
public class SO_18836900 {
public static void main(String[] args) {
// build a collection of random ints
ArrayList<Integer> randInts = new ArrayList();
for (int i = 0; i < 50; i ++) {
randInts.add((int)(Math.random() * 5));
}
// create a collection with all 3s filtered out
ArrayList<Integer> filtered = filterOut(randInts, 3);
System.out.println(filtered);
System.out.println(filtered.size());
// create a collection with a 99 inserted after each 4
ArrayList<Integer> insertedAfter = insertAfter(randInts, 4, 99);
System.out.println(insertedAfter);
System.out.println(insertedAfter.size());
}
static ArrayList<Integer> filterOut(Iterable<Integer> xs, int toRemove) {
ArrayList<Integer> filteredInts = new ArrayList();
for (int x : xs) {
if (x != toRemove) filteredInts.add(x);
}
return filteredInts;
}
static ArrayList<Integer> insertAfter(Iterable<Integer> xs, int trigger, int toInsert) {
ArrayList<Integer> insertedAfter = new ArrayList();
for (int x : xs) {
insertedAfter.add(x);
if (x == trigger) insertedAfter.add(toInsert);
}
return insertedAfter;
}
}
if (randInts.get(i) == removeInt)
randInts.remove(randInts.get(i));
i++;
You're never checking stopping conditions. Fix is:
while (randInts.contains(removeInt) )
{
i=0;
while(i<randInts.size()){
if (randInts.get(i) == removeInt)
randInts.remove(randInts.get(i));
i++;
}
}
Dont use == on "Integers" you are comparing references.
Either unbox into int or use equals(
Say I have the following code:
public static ArrayList<Integer> doSomething(int n) {
ArrayList<Integer> list = new ArrayList<Integer>();
if (n <= 0)
return list ;
list = ListMethods.doSomething(n - 1);
list.add(n);
return list;
Is this any slower than this code:
public static ArrayList<Integer> doSomething(int n) {
ArrayList<Integer> list = null;
if (n <= 0)
return list = new ArrayList<Integer>();
list = ListMethods.doSomething(n - 1);
list.add(n);
return list;
I ask because one of my lecturers uses the latter code in his notes, whereas I've seen other guides online use the former. Is it just personal preference, or is there a speed difference? Additionally, if there is a speed difference, is it too small to be concerned with?
Yes, the first code is slower. For every value of n greater than 0, you end up with the first part equivalent to:
ArrayList<Integer> list = new ArrayList<Integer>();
list = ListMethods.doSomething(n - 1);
There's no point in creating a new ArrayList object and immediately assigning a different value to the same variable.
The second code is better, but could still be improved significantly in terms of readability:
public static ArrayList<Integer> doSomething(int n) {
if (n <= 0) {
return new ArrayList<Integer>();
}
ArrayList<Integer> list = doSomething(n - 1);
list.add(n);
return list;
}
This only uses a list variable if it actually needs to. It's pointless to even declare it for the n <= 0 case, where you're just going to return a new ArrayList<Integer>.
Add a method void removeFirst(int newVal) to the IntegerList class that removes the first occurrence of a value from the list. If the value does not appear in the list, it should do nothing (but it's not an error). Removing an item should not change the size of the array, but note that the array values do need to remain contiguous, so when you remove a value you will have to shift everything after it down to fill up its space. Also remember to decrement the variable that keeps track of the number of elements.
Please help, I have tried all of the other solutions listed on this site regarding "removing an element from an array" and none have worked.
This method supports the same functionality as Collection.remove() which is how an ArrayList removes the first matching element.
public boolean remove(int n) {
for (int i = 0; i < size; i++) {
if (array[i] != n) continue;
size--;
System.arraycopy(array, i + 1, array, i, size - i);
return true;
}
return false;
}
Rather than write this code yourself, I suggest you look at Trove4J's TIntArrayList which is a wrapper for int[] You can also read the code for ArrayList to see how it is written.
You could do this:
int count; //No of elements in the array
for(i=0;i<count;i++)
{
if(Array[i]==element )
{
swap(Array,i,count);
if(count)
--count;
break;
}
}
int swap(int Array[],int i,int count)
{
int j;
for(j=i;j<=count-i;j++)
a[i]=a[i+1];
}
This is not the Full Implementation.You have to create a class and do this.
Using the method below
public static <TypeOfObject> TypeOfObject[] removeFirst(TypeOfObject[] array, TypeOfObject valueToRemove) {
TypeOfObject[] result = Arrays.copyOf(array, array.length - 1);
List<TypeOfObject> tempList = new ArrayList<>();
tempList.addAll(Arrays.asList(array));
tempList.remove(valueToRemove);
return tempList.toArray(result);
}
You can remove the first element of any array by calling the method as demonstrated in the below JUnit test.
#Test
public void removeFirstTest() {
// Given
Integer valToRemove = 5;
Integer[] input = {1,2,3,valToRemove,4,valToRemove,6,7,8,9};
Integer[] expected = {1,2,3,4,valToRemove,6,7,8,9};
// When
Integer[] actual = removeFirst(input, valToRemove);
// Then
Assert.assertArrayEquals(expected, actual);
}