I am trying to create a method that will recursively reverse an ArrayList of generics, and am running into issues with the declaration of my reversedList array (see line 4 of code below).
As the code stands, I receive the error:
cannot find symbol Class: E
The only way I have found to stop the error is by declaring reversedList inside the method, but then it will reset every time it recurses.
import java.util.ArrayList;
import java.util.List;
public class ListRecursive<E>{
public static List<E> reversedList= new ArrayList<E>();
public static <E> void reverse(ArrayList<E> inputList){
E firstitem = null;
if (inputList.size() == 0 ) {
return;
}
else {
firstitem = inputList.get(0);
inputList.remove(0);
}
reverse(inputList);
reversedList.add( firstitem );
}
Below is the main method, which creates an ArrayList of commmand line arguments and attempts to reverse it using the method above.
public static void main(String args[]){
ArrayList<String> argList = new ArrayList<>();
ArrayList<Double> numericArgs = new ArrayList<>();
for (String s : args) {
argList.add(s);
try {
numericArgs.add(Double.parseDouble(s));
}
catch (NumberFormatException e) {
System.out.println(e.getMessage() + "is not numeric...skipping");
}
}
System.out.print("Command line arguments before reversal: ");
for (int i=0; i<argList.size(); i++)
System.out.print(argList.get(i)+ " ");
System.out.println();
reverse(argList);
System.out.print("Command line arguments afterreversal: ");
for (int i=0; i<argList.size(); i++)
System.out.print(argList.get(i)+ " ");
System.out.println();
}
Presuming that you.
Wanted to do it recursively
Didn't want to destroy the original list.
And didn't want to allocate the new List external to the method.
You can do the following:
public static <E> List<E> reverse(List<E> inputList) {
List<E> ret = new ArrayList<>();
E o = inputList.remove(0);
if (inputList.size() > 0) {
ret = reverse(inputList);
}
// at this point they will be on the stack in reverse order.
// so add them to the stack in that order.
ret.add(o);
// return the orginal list to its initial state by inserting them at the beginning.
inputList.add(0, o);
return ret;
}
Calling with this.
List<Integer> ints = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5));
System.out.println(reverse(ints));
System.out.println(ints);
Produces this output.
[5, 4, 3, 2, 1]
[1, 2, 3, 4, 5]
A non-recursive solution would be, of course, trivial.
Note: The passed List must support List.remove() and be mutable for this to work. If you declare your list using List.of() or Arrays.asList() you must pass your list as an argument to the ArrayList<>() constructor.
First of all, if it's a utility method, why store the parameter, if not, then why is it static. You also don't need multiple instances, as method parameters in java are pass-by-reference. More importantly, recursive means your list will be limited to your call stack limit.
Try It Online
public static <E> void reverse(List<E> list) {
for (int i=0;i<list.size()/2;i++) {
E temp = list.get(i);
list.set(i, list.get(list.size()-i-1));
list.set(list.size()-i-1, temp);
}
}
Related
Problem
I have a task that reads as follows:
Implement an IntegerList class with a Vector list object attribute that contains a collection of integers. Implement the findMedian () method which, for a given object from o of the IntegerList class, returns a number m from the vector o.list such that there are at least half of the numbers less than or equal to m, and the numbers greater than or equal to m are also at least half:
For example, for [1, 4, 1, 3, 5, 7] it will be the number 4, and for [1, 1, 1, 2, 2] it will be the number 1 and only 1. If the vector is empty then the method is supposed to throw an IllegalArgumentException exception.
What I tried?
import java.util.Vector;
public class IntegerList {
Vector<Integer> list =new Vector<Integer>();
public int findMedian(Vector<Integer>list){
if(list.size() ==0){
throw new IllegalArgumentException();
}
int result =0;
return result;
}
}
public class Main {
public static void main(String[] args){
IntegerList v = new IntegerList();
v.list.add(2);
v.list.add(3);
v.list.add(4);
v.list.add(9);
System.out.println(v.findMedian(v.list));
}
}
My question:
Why this not working?
What would you change to even better solve this problem?
It is working, but only on empty list. To make it work: we should apply what we learned ..and little try.
Voila:
public int findMedian(Vector<Integer> list) {
if (list == null || list.isEmpty()) {
throw new IllegalArgumentException("'list' is null or empty");
} // from here: list not null and list.size() > 0 ... :
// sort the "list":
java.util.Collections.sort(list); // if you may not modify the list: create a copy first! (the list remains sorted, also when leaving the method...
// return "middle" element:
return list.get(list.size()/2);
}
javadoc
Surprisingly the code:
List<Integer> list = Arrays.asList(1, 3, 2);
list.sort(Comparator.comparingInt(Integer::intValue));
System.out.println(list); // prints [1, 2, 3]
Doesn't throw UnsupportedOperationException in my code. But the list is modified.
So my question is: am I doing something wrong or immutable can be modified? It cannot be resized though.(so isn't the better name for this non-resizable?)
Edit: immutable of course
Well the List is mutable in java so it can be changed,this means we can change an item in a list by accessing it directly as part of the assignment statement.
If you want to make an unmodifiable List you should check public static <T> List<T> unmodifiableList(List<? extends T> list) { method from Collections class
Here is an example
List<Integer> list = Arrays.asList(1, 3, 2); // you have created a mutable List
list.sort(Comparator.comparingInt(Integer::intValue));
System.out.println(list); // prints [1, 2, 3]
List<Integer> list2 = Collections.unmodifiableList(list);
list2.sort(Comparator.comparingInt(Integer::intValue));
System.out.println(list); // throws UnsupportedOperationException
And yes they are non-resizable if we try to add a new value in our unmodifiableList it will throw UnsupportedOperationException
list2.add(3);// throws UnsupportedOperationException
Arrays.asList() does not say anything about "immutable" or "unmodifiable". It only states that the list is fixed-size. You can still change elements, but you cannot add any, as the list would have to be resized. #Typhon's answer gives you good details on immutability.
package stackoverflow;
import java.util.Arrays;
import java.util.List;
public class FixedSize {
public static void main(final String[] args) {
final List<String> fsl = Arrays.asList("A", "B", "C");
System.out.println("List before change: " + fsl.size());
for (final String i : fsl) {
System.out.println("\t" + i);
}
try { // this will fail
fsl.add("1");
System.out.println("Did not fail for some strange reason");
} catch (final Exception e) {
System.out.println("Fails as expoected");
}
fsl.set(1, "LOL");
System.out.println("List after change: " + fsl.size());
for (final String i : fsl) {
System.out.println("\t" + i);
}
}
}
This is a homework lab for school. I am trying to reverse a LinkedList, and check if it is a palindrome (the same backwards and forwards). I saw similar questions online, but not many that help me with this. I have made programs that check for palindromes before, but none that check an array or list. So, first, here is my isPalindrome method:
public static <E> boolean isPalindrome(Collection<E> c) {
Collection<E> tmp = c;
System.out.println(tmp);
Collections.reverse((List<E>) c);
System.out.println(c);
if(tmp == c) { return true; } else { return false; }
}
My professor wants us to set the method up to accept all collections which is why I used Collection and cast it as a list for the reverse method, but I'm not sure if that is done correctly. I know that it does reverse the list. Here is my main method:
public static void main(String...strings) {
Integer[] arr2 = {1,3,1,1,2};
LinkedList<Integer> ll2 = new LinkedList<Integer>(Arrays.asList(arr2));
if(isPalindrome(ll2)) { System.out.println("Successful!"); }
}
The problem is, I am testing this with an array that is not a palindrome, meaning it is not the same backwards as it is forwards. I already tested it using the array {1,3,1} and it works fine because that is a palindrome. Using {1,3,1,1,2} still returns true for palindrome, though it is clearly not. Here is my output using the {1,3,1,1,2} array:
[1, 3, 1, 1, 2]
[2, 1, 1, 3, 1]
Successful!
So, it seems to be properly reversing the List, but when it compares them, it assumes they are equal? I believe there is an issue with the tmp == c and how it checks whether they are equal. I assume it just checks if it contains the same elements, but I'm not sure. I also tried tmp.equals(c), but it returned the same results. I'm just curious is there is another method that I can use or do I have to write a method to compare tmp and c?
Thank you in advance!
Tommy
In your code c and tmp are links to same collection and tmp == c will be always true. Your must clone your collection to new instance, for example: List<E> tmp = new ArrayList(c);.
Many small points
public static <E> boolean isPalindrome(Collection<E> c) {
List<E> list = new ArrayList<>(c);
System.out.println(list);
Collections.reverse(list);
System.out.println(list);
return list.equals(new ArrayList<E>(c));
}
Reverse only works on an ordered list.
One makes a copy of the collection.
One uses equals to compare collections.
public static void main(String...strings) {
int[] arr2 = {1, 3, 1, 1, 2};
//List<Integer> ll2 = new LinkedList<>(Arrays.asList(arr2));
List<Integer> ll2 = Arrays.asList(arr2);
if (isPalindrome(ll2)) { System.out.println("Successful!"); }
}
You need to copy the Collection to a List / array. This has to be done, since the only ordering defined for a Collection is the one of the iterator.
Object[] asArray = c.toArray();
You can apply the algorithm of your choice for checking if this array is a palindrom to check, if the Collection is a palindrom.
Alternatively using LinkedList it would be more efficient to check, if the list is a palindrom without creating a new List to reverse:
public static <E> boolean isPalindrome(Collection<E> c) {
List<E> list = new LinkedList<>(c);
Iterator<E> startIterator = list.iterator();
ListIterator<E> endIterator = list.listIterator(list.size());
for (int i = list.size() / 2; i > 0; i--) {
if (!Objects.equals(startIterator.next(), endIterator.previous())) {
return false;
}
}
return true;
}
Overview
I have an arrayList that holds multiple int arrays that have two parameters, key and value. (I know there exists a map library, but for this task I wish to use an arrayList).
Imagine my arrayList has the following arrays:
[3, 99][6, 35][8, 9][20, 4][22, 13][34, 10]
As you can see, they are in order by the index, which is done when I first add them to the arrayList.
My problem
if I want to add an array to this arrayList it would appended to the end of the list, whereas I want to add it to the correct position in the list.
I'm fairly new to arrayLists, and as such was wondering if there exists an elegant solution to this problem that I have not come across.
Current thoughts
Currently, my solution would be to iterate over the arrayList, then for every array temporally store the key (array[0]), I would then iterate over again and add my array in the correct position (where it's key is in-between two other keys).
Your idea of iterating through is correct; however there is no need to perform the iteration twice. Finding the right index and inserting the element can be done in one loop. ArrayList has a method add(int, E) that can insert an element into any position in the list. Try this:
//the value you want to insert
int[] toInsert = {someValue, someOtherValue};
//assume theList is the list you're working with
for(int index = 0; index < theList.size() -1; index ++)
{
int key = theList.get(index)[0];
int nextKey = theList.get(index + 1)[0];
//if we've reached the correct location in the list
if (toInsert[0] > key && toInsert[0] < nextKey)
{
//insert the new element right after the last one that was less than it
theList.add(index + 1,toInsert);
}
}
Note that this method assumes that the list is sorted to begin with. If you want to make that a guarantee, look into some of the other answers describing sorting and Comparators.
It may be more elegant to produce a class to hold your two values and ensure that implements Comparable, as shown below:
public class Foo implements Comparable<Foo> {
private int x; // your left value
private int y; // your right value
// Constructor and setters/getters omitted
public int compareTo(Foo o) {
return Integer.compare(x, o.getX());
}
}
Then add and sort as follows:
List<Foo> listOfFoos = new ArrayList<Foo>;
// ...
listOfFoos.add(new Foo(33,55));
Collections.sort(listOfFoos);
That would be the most readable solution. There may be faster options, but only optimise if you can prove this part is a bottleneck.
First Option
If you want to be able to sort your array you should be storing Comparable Objects.
So, you can create a Class that will hold your two value array and implement the Comparable interface.
If you chose this option, after adding the element all you need to do is to call .sort() on your List.
Second Option
You can define Comparator that you can use for sorting. This would be reusable and would allow you to keep your two dimensional arrays. You will also have to sort after each time you add.
Third Option
You could define your Comparator on the fly as shown in this particular question:
Java Comparator class to sort arrays
you can do the following:
import java.util.ArrayList;
public class AddElementToSpecifiedIndexArrayListExample {
public static void main(String[] args) {
//create an ArrayList object
ArrayList arrayList = new ArrayList();
//Add elements to Arraylist
arrayList.add("1");
arrayList.add("2");
arrayList.add("3");
/*
To add an element at the specified index of ArrayList use
void add(int index, Object obj) method.
This method inserts the specified element at the specified index in the
ArrayList.
*/
arrayList.add(1,"INSERTED ELEMENT");
System.out.println("ArrayList contains...");
for(int index=0; index < arrayList.size(); index++)
System.out.println(arrayList.get(index));
}
}
/*
Output would be
ArrayList contains...
1
INSERTED ELEMENT
2
3
*/
There is also a version of add that takes the index at which to add the new item.
int i;
for(i=0; i<arr.size(); i++){
if(arr.get(i)[0] >= newArr[0]){
arr.add(i, newArr);
}
}
if(i == arr.size())
arr.add(i, newArr)
Use a Comparator of int[] along with binarySearch :
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
public class Main
{
public static void main(String[] argv)
{
ArrayList<int[]> list = new ArrayList<int[]>();
list.add(new int[] { 3, 99 });
list.add(new int[] { 6, 35 });
list.add(new int[] { 8, 9 });
list.add(new int[] { 20, 4 });
list.add(new int[] { 22, 13 });
list.add(new int[] { 34, 10 });
Compar compar = new Compar();
addElement(list, new int[] { 15, 100 }, compar);
for(int[] t : list)
{
System.out.println(t[0]+" "+t[1]);
}
}
private static void addElement(ArrayList<int[]> list, int[] elem, Compar compar)
{
int index = Collections.binarySearch(list, elem, compar);
if (index >= 0)
{
list.add(index, elem);
return;
}
list.add(-index - 1, elem);
}
static class Compar implements Comparator<int[]>
{
#Override
public int compare(int[] a, int[] b)
{
return a[0] - b[0];
}
}
}
This is the requirement where I am facing problem finding the solution.
Problem:
I have ArrayList with data 20, 10, 30, 50, 40, 10.
If we sort this in ascending order the result will be 10, 10, 20, 30, 40, 50.
But I need the result as 3, 1, 4, 6, 5, 2.(The index of each element after sorting).
Strictly this should work even if there are repetitive elements in the list.
Please share your idea/approach solving this problem.
Here is my solution. We define a comparator to sort a list of indices based on the corresponding object in the list. That gives us a list of indices which is effectively a map: indices[i] = x means that the element at location x in the original list is at element i in the sorted list. We can then create a reverse mapping easily enough.
Output is the indices starting from 0: [2, 0, 3, 5, 4, 1]
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
class LookupComparator<T extends Comparable<T>> implements Comparator<Integer> {
private ArrayList<T> _table;
public LookupComparator(ArrayList<T> table) {
_table = table;
}
public int compare(Integer o1, Integer o2) {
return _table.get(o1).compareTo(_table.get(o2));
}
}
public class Test {
public static <T extends Comparable<T>> ArrayList<Integer> indicesIfSorted(ArrayList<T> list) {
ArrayList<Integer> indices = new ArrayList<Integer>();
for (int i = 0; i < list.size(); i++)
indices.add(i);
Collections.sort(indices, new LookupComparator(list));
ArrayList<Integer> finalResult = new ArrayList<Integer>();
for (int i = 0; i < list.size(); i++)
finalResult.add(0);
for (int i = 0; i < list.size(); i++)
finalResult.set(indices.get(i), i);
return finalResult;
}
public static void main(String[] args) {
ArrayList<Integer> list = new ArrayList<Integer>();
list.add(20);
list.add(10);
list.add(30);
list.add(50);
list.add(40);
list.add(10);
ArrayList<Integer> indices = indicesIfSorted(list);
System.out.println(indices);
}
}
My idea is creating 1 more attribute call index beside your value (in each data of aray). It will hold your old index, then u can take it out for using.
Building off what Hury said, I think the easiest way I can see to do this is to make a new data type that looks something like:
public class Foo {
private Integer value;
private int origPosition;
private int sortedPosition;
/*Constructors, getters, setters, etc... */
}
And some psuedo code for what to do with it...
private void printSortIndexes(ArrayList<Integer> integerList) {
// Create an ArrayList<Foo> from integerList - O(n)
// Iterate over the list setting the origPosition on each item - O(n)
// Sort the list based on value
// Iterate over the list setting the sortedPosition on each item - O(n)
// Resort the list based on origPositon
// Iterate over the lsit and print the sortedPositon - O(n)
}
That won't take long to implement, but it is horribly inefficient. You are throwing in an extra 4 O(n) operations, and each time you add or remove anything from your list, all the positions stored in the objects are invalidated - so you'd have to recaculate everything. Also it requires you to sort the list twice.
So if this is a one time little problem with a small-ish data set it will work, but if you trying to make something to use for a long time, you might want to try to think of a more elegant way to do it.
Here is the approach of adding an index to each element, written out in Scala. This approach makes the most sense.
list.zipWithIndex.sortBy{ case (elem, index) => elem }
.map{ case (elem, index) => index }
In Java you would need to create a new object that implements comperable.
class IndexedItem implements Comparable<IndexedItem> {
int index;
int item;
public int compareTo(IndexItem other) {
return this.item - other.item;
}
}
You could then build a list of IndexedItems, sort it with Collection.sort, and then pull out the indices.
You could also use Collections.sort on the original list followed by calls to indexOf.
for (int elem : originalList) {
int index = newList.indexOf(elem);
newList.get(index) = -1; // or some other value that won't be found in the list
indices.add(index);
}
This would be very slow (all the scans of indexOf), but would get the job done if you only need to do it a few times.
A simplistic approach would be to sort the list; then loop on the original list, find the index of the element in the sorted list and insert that into another list.
so a method like
public List<Integer> giveSortIndexes(List<Integer> origList) {
List<Integer> retValue = new ArrayList<Integer>();
List<Integer> originalList = new ArrayList<Integer>(origList);
Collections.sort(origList);
Map<Integer, Integer> duplicates = new HashMap<Integer, Integer>();
for (Integer i : originalList) {
if(!duplicates.containsKey(i)) {
retValue.add(origList.indexOf(i) + 1);
duplicates.put(i, 1);
} else {
Integer currCount = duplicates.get(i);
retValue.add(origList.indexOf(i) + 1 + currCount);
duplicates.put(i, currCount + 1);
}
}
return retValue;
}
I haven't tested the code and it might need some more handling for duplicates.