I'm currently working on an assignment with a number of methods with parameters of type Set. In order to use these parameters in my program they have to be converted to arrays, and the conversion has to be done with time complexity no greater than O(N). I'm stumped, as I don't know the type of the set, or any properties at all about it. I can get the size of the set, but that's about it. I am not allowed to use ArrayList, or any other List or Set class. toArray() doesn't work, the compiler says it can't find the symbol. I obviously can't create a generic type array. What do I do now?
Here's a sample of the code. there are 6 more methods with headers similar to it.
public boolean equals(Set<T> s) {
T[] sArray = s.toArray(new T[s.size()]);
My error messages are as follows:
ArraySet.java:241: error: generic array creation
T[] sArray = s.toArray(new T[s.size()]);
^
ArraySet.java:241: error: cannot find symbol
T[] sArray = s.toArray(new T[s.size()]);
^
symbol: method toArray(T[])
location: variable s of type Set<T>
where T is a type-variable:
T extends Comparable<? super T> declared in class ArraySet
Edit: Updated so that ArraySet actually behaves like a Set...
Here's an example of how you could implement your equals(Set<T> s) method. Since not of all ArraySet was included in your question, I've had to assume how your ArraySet will work, and that it supports any reference type (generics).
The equal(Set<T> s) method, simply loops through the array and uses the contains(Object o) method on s. This is O(n) since worst case scenario you loop through all n element of the array. It will continue checking until it finds that it doesn't contain an element or all elements have been checked. Note that the loop won't start if the size() of the Set and the length of the array are not equal.
import java.util.Set;
public class ArraySet<T> {
private T[] array;
private int count;
private final int DEFAULT_CAPACITY = 16;
public ArraySet() {
array = (T[]) new Object[DEFAULT_CAPACITY];
count = 0;
}
public void add(T e) {
if (count < array.length && !contains(e)) {
array[count++] = e;
}
}
public boolean contains(T e) {
boolean hasElement = false;
int i = 0;
while (!hasElement && i < count) {
hasElement = array[i++].equals(e);
}
return hasElement;
}
public boolean equals(Set<T> s) {
boolean isEqual = s.size() == count;
int i = 0;
while (isEqual && i < count) {
isEqual = s.contains(array[i++]);
}
return isEqual;
}
}
Example of using ArraySet's equals(Set<T> s) method:
import java.util.HashSet;
import java.util.Set;
public class ArraySetTest {
public static void main(String[] args) {
Set<String> stringSet = new HashSet<>();
stringSet.add("Foo1");
stringSet.add("Foo2");
ArraySet<String> arraySet = new ArraySet<>();
arraySet.add("Foo1");
arraySet.add("Foo2");
System.out.println(arraySet.equals(stringSet));
}
}
Related
While going through the Effective Java examples, I failed to understand below code.
How this anonymous Abstract class return List of objects without iterating through array elements or calling the add() method.
what's going on behind the scenes in below code?
public static void main(String[] args) {
int a[] = new int[10];
for (int i = 0; i < a.length; i++) {
a[i] = i;
}
List<Integer> list = intArrayAsList(a);
System.out.println(list);
}
static List<Integer> intArrayAsList(final int[] a) {
if (a == null) {
throw new NullPointerException();
}
return new AbstractList<Integer>() {
#Override
public Integer get(int index) {
return a[index];
}
#Override
public int size() {
return a.length;
}
#Override
public Integer set(int index, Integer element) {
int oldVal = a[index];
a[index] = element;
return oldVal;
}
};
}
The reason add wasn't called is because it never created a new list. The new AbstractList is just holding a reference to the array 'a' and when you iterate over your new AbstractList, it will simply lookup in the array.
For fun, try to remove the keyword 'final' from that line:
static List<Integer> intArrayAsList(final int[] a) {
It will not compile anymore. The reason is because the AbstractList is an anonymous class and in order to be able to use a variable, that variable needs to be final.
new AbstractList<Integer>() { ... } is not an abstract class. It is a subclass of the abstract type AbstractList<Integer>. That particular type implements almost all List<Integer> methods in terms of just two abstract methods: get and set (size is also needed for some operations), whose implementation is provided by your example.
In particular, there was no need to call the add method because the provided implementation is a closure wrapping the supplied int[]. The AbstractList's implementation of iterator() will internally delegate to the provided implementation of get.
Hi I'm very new to Java and in this code, I think I'm not creating the Bag correctly in the Main? Please help thanks!
Exception in thread "main" java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Ljava.lang.Comparable;
at mid.Bag.(Bag.java:12)
at mid.Bag.main(Bag.java:91)
public class Bag<T extends Comparable<T>> implements Iterable<T> {
private int MAX_ITEMS = 10; // initial array size
private int size;
private T[] data;
public Bag( ) {
data = (T []) new Object[MAX_ITEMS];
size = 0;
}
public void add(T newItem) {
// check if it's full, then extend (array resizing)
if (size == data.length) {
T[ ] temp = (T [ ] ) new Object[data.length*2];
for (int i = 0; i < size; ++i)
temp[i] = data[i];
// reassign data to point to temp
data = temp;
}
// then do the assignment
data[size++] = newItem; // assign newItem in the next-available slot
}
public Iterator<T> iterator() {
return new BagIterator();
}
/***************************
* nested class BagIterator
***************************/
class BagIterator implements Iterator<T> {
// instance member
private int index;
// (0) constructor
public BagIterator() {
index = 0;
}
// (1)
public boolean hasNext() {
return (index < size); // size in the outer Bag<E>
}
// (2)
public T next() {
/*
T temp = data[index]; // save the element value
index++; // increment index
return temp;
*/
return data[index++];
}
public static void main(String[ ] args) {
Bag<String> bag1=new Bag<String>();
bag1.add("good");
bag1.add("fortune");
bag1.add("billionarie");
for (String x: bag1)
System.out.println(x);
}
Yes, you're creating an Object[] and then trying to cast it to T[], which the compiler is converting to a cast to Comparable[] (using the raw Comparable type) due to your constraint on T.
Arrays and generics don't work terribly nicely together, basically.
It would probably be simpler to make your data field just an Object[] and cast individual values where necessary.
Here:
data = (T []) new Object[MAX_ITEMS];
you are constructing an Object array and trying to cast it to T[]. But you have declared that T inherits from Comparable. So use:
data = (T []) new Comparable[MAX_ITEMS];
You can probably rewrite your constructor as well:
public Bag(Class<T> c, int s) {
// Use Array native method to create array of a type only known at run time
#SuppressWarnings("unchecked")
final T[] dataArray = (T[]) Array.newInstance(c, s);
this.data = dataArray;
}
Then you can use it like:
Bag<String> bag1 = new Bag<>(String.class,10);
That should also work, IMO. The instances of T must be comparable in any case.
I want to add an object to my array. I am trying to create a method so whenever it's called, it adds the generic type object. Here's my code:
public class ArrayObjects<E> implements SomeImp<E>{
private E[] list;
private int maxCapacity, currentSize;
public ArrayObjects(){
maxCapacity = 10;
array = (E[]) new Object[maxCapacity];
}
public void addObj(E obj){
array.add(obj); //Throws an error
}
}
Eclipse shows me an error though. It says "Cannot invoke add(E) on the array type E[ ]"
Does anyone know why does this happen? Do you know of an alternative of adding an object to my generic array?
Thank you!
EDIT:
When I create an instance of a class that instantiates ArrayObjects, and try to add a value to it, it doesn't do it. code:
import packageWhereArrayObjectsIs.*;
public class Test {
private ArrayObjects<Integer> list;
public Test() {
list = new ArrayObjects<Integer>();
Test();
}
private void TestOne() {
for(int i=1; i <= 10; i++)
list.addLast(i);
System.out.println("Should print 1 .. 10");
System.out.println(list);
}
}
The method add() does not exist for arrays. You must access array elements using the correct syntax []:
public void addLast(E obj) {
array[currentSize++] = obj;
}
In order for your list to print nicely, you'll want to add a toString() method to your ArrayObjects class:
public String toString() {
return Arrays.toString(array);
}
To iterate over the elements of your ArrayObjects, you can implement the Iterable interface:
public class ArrayObjects<E> implements Iterable<E>
This requires your class to have an iterator() method that returns an Iterator:
public Iterator<E> iterator() {
class It implements Iterator<E>
{
int position = -1;
public boolean hasNext() {
return position + 1 < currentSize;
}
public E next() {
return array[++position];
}
public void remove() {
throw new UnsupportedOperationException();
}
}
return new It();
}
Finally, this code shows how you can now iterate over your list using an enhanced for loop:
ArrayObjects<Integer> list = new ArrayObjects<Integer>();
for (int i = 0; i < 10; i++) list.addLast(i);
for (Integer i: list) {
System.out.println("Iterating over list! Next element is " + i);
}
You should do something like this, assuming that your actual size is 1 when you add your first element BUT the position will be 0 because it's the first position of the array.
public boolean addObj(E obj){
if(actualSize == maxCapacity){
return false;
}
array[actualSize--] = obj;
return true;
}
I changed the return value to return false if there is no positions left in the array (considering that you won't remove any object in the middle).
Why do you need an array? Why not going with a List?
public class ArrayObjects<E> implements SomeImp<E>{
private List<E> list;
private int maxCapacity;
public ArrayObjects(){
maxCapacity = 10;
list = new ArrayList<E>();
}
public boolean addObj(E obj){
if(list.size() == maxCapacity){
return false;
}
list.add(obj);
return true;
}
}
See that using a List you won't have to deal with the actualSize.
EDIT: as Smac89 points out, it makes no sense to use a list. But keep in mind you will have to find an empty position if the array is not full.
I have defined my own compare function for a priority queue, however the compare function needs information of an array. The problem is that when the values of the array changed, it did not affect the compare function. How do I deal with this?
Code example:
import java.util.Arrays;
import java.util.Comparator;
import java.util.PriorityQueue;
import java.util.Scanner;
public class Main {
public static final int INF = 100;
public static int[] F = new int[201];
public static void main(String[] args){
PriorityQueue<Integer> Q = new PriorityQueue<Integer>(201,
new Comparator<Integer>(){
public int compare(Integer a, Integer b){
if (F[a] > F[b]) return 1;
if (F[a] == F[b]) return 0;
return -1;
}
});
Arrays.fill(F, INF);
F[0] = 0; F[1] = 1; F[2] = 2;
for (int i = 0; i < 201; i ++) Q.add(i);
System.out.println(Q.peek()); // Prints 0, because F[0] is the smallest
F[0] = 10;
System.out.println(Q.peek()); // Still prints 0 ... OMG
}
}
So, essentially, you are changing your comparison criteria on the fly, and that's just not the functionality that priority queue contracts offer. Note that this might seem to work on some cases (e.g. a heap might sort some of the items when removing or inserting another item) but since you have no guarantees, it's just not a valid approach.
What you could do is, every time you change your arrays, you get all the elements out, and put them back in. This is of course very expensive ( O(n*log(n))) so you should probably try to work around your design to avoid changing the array values at all.
Your comparator is only getting called when you modify the queue (that is, when you add your items). After that, the queue has no idea something caused the order to change, which is why it remains the same.
It is quite confusing to have a comparator like this. If you have two values, A and B, and A>B at some point, everybody would expect A to stay bigger than B. I think your usage of a priority queue for this problem is wrong.
Use custom implementation of PriorityQueue that uses comparator on peek, not on add:
public class VolatilePriorityQueue <T> extends AbstractQueue <T>
{
private final Comparator <? super T> comparator;
private final List <T> elements = new ArrayList <T> ();
public VolatilePriorityQueue (Comparator <? super T> comparator)
{
this.comparator = comparator;
}
#Override
public boolean offer (T e)
{
return elements.add (e);
}
#Override
public T poll ()
{
if (elements.isEmpty ()) return null;
else return elements.remove (getMinimumIndex ());
}
#Override
public T peek ()
{
if (elements.isEmpty ()) return null;
else return elements.get (getMinimumIndex ());
}
#Override
public Iterator <T> iterator ()
{
return elements.iterator ();
}
#Override
public int size ()
{
return elements.size ();
}
private int getMinimumIndex ()
{
T e = elements.get (0);
int index = 0;
for (int count = elements.size (), i = 1; i < count; i++)
{
T ee = elements.get (i);
if (comparator.compare (e, ee) > 0)
{
e = ee;
index = i;
}
}
return index;
}
}
So I'm wondering how to create a generic method that, when passed an array of a given type, will return an array of that same type. The code I'm working with currently looks like this:
public class InsertionSort<T extends Comparable<T>> extends Sort<T>
{
public T[] sort (T[] data)
{
for (int index = 1; index < data.length; index++)
{
T key = data[index];
int position = index;
/* Shift larger values to the right */
while (position > 0 && data[position-1].compareTo(key) > 0)
{
data[position] = data[position-1];
position--;
}
data[position] = key;
}
return data;
}
}
The problem: when I pass, say, an Integer[] array onto this method as a parameter, it returns data as a basic Comparable[] or Object[] array rather than an Integer[]. Is there a way to change it so so that, if it gets passed an Integer[] array, it sorts it and returns an array of Integer[], but if it gets passed a String[] array, it sorts it and returns an array of String[]? (and so on for any other type that implements Comparable)
Fundamentally, a Java method cannot return more than one type. You can return a generic type, Object, and type cast it in your calling function.
It can be a bit awkward to work with, but you can do something like this:
public class MyClass {
public <K extends Comparable<K>> K[] getMe(K[] obj) {
return obj;
}
public static void main(String[] args) {
MyClass c = new MyClass();
Integer[] b = {1,2,3};
Integer[] d = c.getMe(b);
for(Integer i : d) {
System.out.println(i);
}
}
}