I have a problem using java.util.Vector and java.util.ArrayList.
I know the capacity or better how many elements will be saved within the vector. So i initialized a java.util.List using an implementation of it leveraging the constructor new Vector<?>(int capacity).
After the initialisation of the List, I used the method set(index, value) but this call results in an IndexOutOfBoundException. Which is quite confusing because i set the capacity to a given value using the constructor.
The following code snippet shows the problem:
public void calculateSimple(List<Stock> values, int n) {
if (n<=0) {
throw new IllegalArgumentException("N must not be zero or negativ");
}
int max = values.size();
result = new Vector<Double>(max);
System.out.println("Size of result "+result.size());
if (max == 0) {
result.add(0.0);
}
if (max <= n) {
n = max;
}
for (int i = 1; i <= n; i++) {
List<Double> subList = values.subList(max-i-n, max-i);
result.set(result.size()-i, calculateSimpleValue(subList, n));
}
}
I know i can solve this problem using simple arrays. I want to ask if there are any bugs within the code or do i have some wrong imaginations about the capacity constructor, concerning the class Vector or any other List implementation.
UPDATE
The question is:
Is it possible to use any kind of java.util data structur in a hybrid way
(Arrays, Dynamic List (or any other))
If you want to create a list initialied with some values, like 0.0 or nulls, here is a quick way to do it:
ArrayList<Double> list = new ArrayList<>(Collections.nCopies(100, value));
The capacity constructor parameter does not mean that such number of elements will be added to ArrayList automatically. It just means the initial size of internal buffer which will be allocated. It can be used if you can estimate in advance how many elements you will have in the list to improve the performance. But you still need to add actual elements to the list. You can do it using the loop:
for(int i=0; i<max; i++) result.add(0.0);
From the java.util.Vector.set() method i can see
/**
* Replaces the element at the specified position in this Vector with the
* specified element.
*
* #param index index of the element to replace
* #param element element to be stored at the specified position
* #return the element previously at the specified position
* #throws ArrayIndexOutOfBoundsException if the index is out of range
* ({#code index < 0 || index >= size()})
* #since 1.2
*/
public synchronized E set(int index, E element) {
if (index >= elementCount)
throw new ArrayIndexOutOfBoundsException(index);
E oldValue = elementData(index);
elementData[index] = element;
return oldValue;
}
so when you are using the set method it is possible that your result.size()-i >= calculateSimpleValue(subList, n) .Where elementCount = elementdata.length in the constructor when you are instantiating the vector.
In the example above , the point where you have used sublist method, if max=n then in that case it will result into a negative value, which can also result into an IndexOutOfBoundException
Related
Say I had a method finalNum() where I want to use this method to pick out the final number in a list i.e. {1,2,10,12} and returns 12
What is the simplest way to do so using a for loop vs a while loop? Can someone show both? I'm new to code and trying to find a simple example.
Since Lists are based on arrays which are zero-indexed, the last element is the element at index list.size() - 1. Using List#get will suffice; there is no need for looping at all.
final List<Integer> list = List.of(1,2,10,12);
final Integer last = list.get(list.size() - 1);//12
If you really want to solve this question for educating purposes, you can take a look at these examples.
Here we loop from the beginning to the end and saving each element of the list to a variable. After we have finished looping we return the value which is by definition the last element of the list
static int finalNum(List<Integer> listOfNumbers) {
int result = 0;
for (int i = 0 ; i < listOfNumbers.length(); ++i) {
result = listOfNumbers.get(i);
}
return result;
}
You can do it the other way around, too:
static int finalNum(List<Integer> listOfNumbers) {
int result = 0;
for (int i = listOfNumbers.length() - 1; i >= 0; --i) {
return listOfNumbers.get(i);
}
throw new IllegalStateException("list contains no elements");
}
That loop goes from the end to the beginning. So the loop does not actually loop. This is mostly not what the developer wants or has intended.
The first example as a while loop
static int finalNum(List<Integer> listOfNumbers) {
int result = 0;
Iterator<Integer> iterator = listOfNumbers.iterator();
while(iterator.hasNext())
result = iterator.next();
}
return result;
}
Here we also loop from the beginning to the end storing everything in a variable which we return as result at the very end.
But after all, none of this is recommend as you can easily access the last element of a list via list.get(list.size() - 1). The above code is by no means code for production.
Is there any efficient way for getting the nth element of a set in Java?
I know 2 ways of doing it:
- By iterating through it until I reach the required element
- By converting it to an ArrayList and getting the elements from that ArrayList
The question is that is there any other way to get the nth element of it quickly. I would mainly need a feature like that for the TreeSets.
EDIT:
For example if I want to select 1000 random elements from a 10 000 000 element long treemap or treeset, very frequently (i.e. every 2-3 seconds), then cloning it to an arraylist all the time is very inefficient, and iterating through so many elements is also inefficient.
If you are sure that you need n elements from random positions in the set (kind of like a statistical sampling), then you may want to consider just iterating through the set once and pick up the samples, by the desired probability, as you iterate through the set. This way is more efficient as you will iterate through the set only once.
The following program demonstrates the idea:
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Random;
import java.util.Set;
import java.util.TreeSet;
public class SamplingFromSet {
public static void main(String[] args) {
Set<String> population = new TreeSet<>();
/*
* Populate the set
*/
final int popSize = 17;
for (int i=0; i<popSize; i++) {
population.add(getRandomString());
}
List<String> sample
= sampleFromPopulation(population, 3 /*sampleSize */);
System.out.println("population is");
System.out.println(population.toString());
System.out.println("sample is");
System.out.println(sample.toString());
}
/**
* Pick some samples for a population
* #param population
* #param sampleSize - number of samples
* #return
*/
private static <T>
List<T> sampleFromPopulation(Set<T> population
, int sampleSize) {
float sampleProb = ((float) sampleSize) / population.size();
List<T> sample = new ArrayList<>();
Iterator<T> iter = population.iterator();
while (iter.hasNext()) {
T element = iter.next();
if (random.nextFloat()<sampleProb) {
/*
* Lucky Draw!
*/
sample.add(element);
}
}
return sample;
}
private static Random random = new Random();
private static String getRandomString() {
return String.valueOf(random.nextInt());
}
}
Output of this program:
population is
[-1488564139, -1510380623, -1980218182, -354029751, -564386445, -57285541, -753388655, -775519772, 1538266464, 2006248253, 287039585, 386398836, 435619764, 48109172, 580324150, 64275438, 860615531]
sample is
[-57285541, -753388655, 386398836]
Update
The above program, however, has a caveat -- since the picking up
of samples in that one walk through the set is done by probability,
the returned sample may, depending on your luck of the day,
have fewer or more samples than specified.
This problem, however, can remedied with a slight change of procedure,
which uses a slightly different method signature:
/**
* Pick some samples from a population
* #param population
* #param sampleSize - number of samples
* #param exactSize - a boolean to control whether or not
* the returned sample list must be of the exact size as
* specified.
* #return
*/
private static <T>
List<T> sampleFromPopulation(Set<T> population
, int sampleSize
, boolean exactSize);
Prevention of oversampling
In the one iteration through the population, we over sample a bit,
and then at the end we drop some samples if we do have too many.
Prevention of undersampling
Note also that, even with oversampling, there is a non-zero probability
that, at the end of the one iteration through the population, we still
get less samples than desired. If that happen (unlikely), we will recursively calling
the same method again as a second try. (This recursion has a probability approaching one
to terminate because it is very unlike that, in repeated recursive
call into the method, we consistently get undersampling.)
The following code implements the new sampleFromPopulation() method:
private static <T>
List<T> sampleFromPopulation(Set<T> population
, int sampleSize
, boolean exactSize) {
int popSize = population.size();
double sampleProb = ((double) sampleSize) / popSize;
final double OVER_SAMPLING_MULIT = 1.2;
if (exactSize) {
/*
* Oversampling to enhance of chance of getting enough
* samples (if we then have too many, we will drop them
* later)
*/
sampleProb = sampleProb * OVER_SAMPLING_MULIT;
}
List<T> sample = new LinkedList<>(); // linked list for fast removal
Iterator<T> iter = population.iterator();
while (iter.hasNext()) {
T element = iter.next();
if (random.nextFloat()<sampleProb) {
/*
* Lucky Draw!
*/
sample.add(element);
}
}
int samplesTooMany = sample.size() - sampleSize;
if (!exactSize || samplesTooMany==0) {
return sample;
} else if (samplesTooMany>0) {
Set<Integer> indexesToRemoveAsSet = new HashSet<>();
for (int i=0; i<samplesTooMany; ) {
int candidate = random.nextInt(sample.size());
if (indexesToRemoveAsSet.add(candidate)) {
/*
* add() returns true if candidate was not
* previously in the set
*/
i++; // proceed to draw next index
}
}
List<Integer> indexesToRemoveAsList
= new ArrayList<>(indexesToRemoveAsSet);
Collections.sort(indexesToRemoveAsList
, (i1, i2) -> i2.intValue() - i1.intValue()); // desc order
/*
* Now we drop from the tail of the list
*/
for (Integer index : indexesToRemoveAsList) {
sample.remove((int) index); // remove by index (not by element)
}
return sample;
} else {
/*
* we were unluckly that we oversampling we still
* get less samples than specified, so here we call
* this very same method again recursively
*/
return sampleFromPopulation(population, sampleSize, exactSize);
}
}
If your requirement is to select random elements out of a rather huge set then you should ask yourself whether a set is the best fit for that.
If you want to use the built-in sets there are several challenges you'd face.
TreeSet
A TreeSet is an ordered set and thus would allow you to access the n-th element. However, you'd have to iterate to position n since there is no array that allows random access like an ArrayList would. As the name implies the nodes in a TreeSet form a tree and the nodes most likely are stored anywhere in memory. Because of this to get the n-th element you'd have to start at the first node and hop from node to node until you reach position n - which is similar to how you'd do it in a LinkedList.
If all you want to do is select a random element there are several options:
If the set doesn't change (or not often) you could create a matching array or ArrayList and use random access.
Iterate over the set for a random number of times.
Generate a random key and look up the next higher/lower element, e.g. by using tailSet(randomKey) and getting the first element of that tail set. Of course you'd have to handle random keys that are outside the elements' range. That way a lookup would basically be a binary search.
HashSet
HashSets basically consist of 2 things: an array of buckets and a linked list or tree for collisions, i.e. if 2 elements would be mapped to the same bucket. Getting a random element might then be done by accessing a random bucket (this would be random access) and then iterating over the elements in that bucket for a random number of times.
int index = hash(value, size);
if (array.get(index) == null) {
array.add(index, new LinkedList<String>());
}
I have an array of LinkedLists: Arraylist<.LinkedList<.String>>, and I want to add a LinkedList in the array index given if one hasn't been initialized in it yet. Problem is, the index hashes to some number, but the index it goes to doesn't exist, since no LinkedList has been initialized in that index yet, but that's why i am doing if(array.get(index) == null) add a LinkedList, but apparently that's an incorrect comparison to do.
I tried .isEmpty(), null, and .equals(null), they don't work.
The ArrayList doesn't auto-grow, you have to grow it yourself:
int index = hash(value, size);
// grow
if (array.size() <= index) {
array.ensureCapacity(index + 1);
while (array.size() <= index)
array.add(null);
}
if (array.get(index) == null) {
array.set(index, new LinkedList<String>());
}
Note my change of array.add(index, ...) to array.set(index, ...) (docs): add will insert (and shift the rest of the array) while set will overwrite the element at the given index.
As long as you control hash you know the upper limits of its return value (let's call this limit) and you should only need to initialise your array once:
// initialise
ArrayList<LinkedList<String>> array = new ArrayList<>();
array.ensureCapacity(limit);
for (int i = 0; i < limit; ++i)
array.add(null);
// ...
// use
int index = hash(value, size); // hash(...) returns values in 0..limit-1
if (array.get(index) == null) {
array.set(index, new LinkedList<String>());
}
As Tamas Rev stated: you don't have to reinvent the wheel, just use a HashMap. As an additional bonus, HashMap will most likely be faster and generally be more memory efficient (the above scheme allocates an array of limit elements while HashMap can deal with any key type of any size).
I have a method that adds an object to an array but it adds it based on order. So lets say I have an array that has an apples, and cola. If I wanted to add a banana it would go between those two objects. But I keep getting errors when I run my jUnit tests. Here is the code:
/**
* Adds an item to the list. This method assumes that the list is already
* sorted in alphabetical order based on the names of the items in the list.
*
* The new item will be inserted into the list in the appropriate place so
* that the list will remain alphabetized by names.
*
* In order to accomodate the new item, the internal array must be re-sized
* so that it is one unit larger than it was before the call to this method.
*
* #param itemToAdd refers to a Listable item to be added to this list
*/
public void add(Listable itemToAdd) {
int i;
Listable[] newItems = new Listable[items.length+1];
for(i=0; i<items.length;i++){
if(items[i].getName().compareTo(itemToAdd.getName()) < 0){
newItems[i] = items[i];
} else{
break;
}
}
int str=i;
for(i=str+1;i<items.length;i++){
newItems[i+1] = items[i];
}
newItems[str] = itemToAdd;
}
I keep getting an error that states that the test expected <14> but got <0> so now I think that means its my constructor thats the problem:
/**
* This constructor creates an empty list by creating an internal array
* of size 0. (Note that this is NOT the same thing as setting the internal
* instance variable to null.)
*/
public SortedListOfImmutables() {
int i = 0;
items = new Listable[0];
//orders the list
for( i=0;i<items.length;i++){
if(Food.FOOD_OBJECTS[i].getName().compareTo(Food.FOOD_OBJECTS[i+1].getName()) < 0){
items[i] = Food.FOOD_OBJECTS[i];
}else{
items[i+1] = Food.FOOD_OBJECTS[i];
}
}
}
I think atleast one of your problems is with this for loop:
for(i=str+1;i<items.length;i++){
newItems[i+1] = items[i];
}
I'll just use an example list to show you why. Lets say our items list contains {apple, banana, orange, pineapple}. Then we want to insert "grape" which should be inserted between "banana" and "orange". The first for loop does does 3 iterations before breaking (putting "apple" and "banana" into newItems, then breaks on i=2) You assign str = 2 which is the index "grape" should be inserted. But then when inserting the remaining elements, you set i=str+1 which would be 3 in this case, so
newItems[i+1] = items[i];
would put "pineapple" into index 4 of newItems, which is correct but you completely skip putting what is in index 2 in items ("orange") into the newItems at index 3.
To fix this, you either want to do:
for(i=str;i<items.length;i++){
newItems[i+1] = items[i];
}
or:
for(i=str+1;i<items.length;i++){
newItems[i] = items[i-1];
}
Goal
I am making a Java class that will give enhanced usability to arrays, such as add, remove, and contains methods. I figured the best solution is to make a class (called ArrayPP) that has a type parameter T. This way, the user can interact with the ArrayPP object as easily as they can with an array of the same type.
Problem
I quickly found that such methods as add will require the creation of a separate array, and end up changing the target array t from an array of Ts into an array of Objects. As you may guess, this totally destroys the usability, and when I try to do something like
File[] f = new File[0];
ArrayPP<File> appF = new ArrayPP(f);
appF.add(saveFile);
f = appF.toArray();
the program throws
Exception in thread "main" java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Ljava.io.File;
because the add method has to change the array into an array of Objects, as the Java compiler won't let you make a generic array (T[] t = new T[0]; is bad, but T[] t = (T[]) new Object[0]; is okay). I know from line-by-line debugging that the above code keeps the array t, in this case, as a n array of Files UNTIL the 4th line of the add method is called. Does anyone have a solution that will keep the array t being an array of Ts and not an array of Objects?
Sample Code
Below is a VERY watered-down version of my class.
public class ArrayPP<T>
{
T[] t;
/**
* Creates a new Array++ to manage the given array.
* <h3>Analogy:</h3>
* <tt>ArrayPP<String> s = new ArrayPP(args);</tt><br/>
* is analogous to<br/>
* <tt>String s[] = args;</tt>
* #param array The array to be managed
*/
public ArrayPP(T[] array)
{
t = array;
}
/**
* Appends a value to the end of the array
* #param val the value to be appended
* #return the resulting array.
*/
public ArrayPP add(T val)
{
T[] temp = (T[]) new Object[t.length + 1];
System.arraycopy(t, 0, temp, 0, t.length);
temp[temp.length - 1] = val;
t = (T[])temp;
return this;
}
/**
* Returns the array at the core of this wrapper
* #return the array at the core of this wrapper
*/
public T[] toArray()
{
return t;
}
}
Possible Solution?
After looking at other questions about generic arrays, I think I have a solution:
Instead of
/**
* Appends a value to the end of the array
* #param val the value to be appended
* #return the resulting array.
*/
public ArrayPP add(T val)
{
T[] temp = (T[]) new Object[t.length + 1];
System.arraycopy(t, 0, temp, 0, t.length);
temp[temp.length - 1] = val;
t = (T[])temp;
return this;
}
will this work?
/**
* Appends a value to the end of the array
* #param val the value to be appended
* #return the resulting array.
*/
public ArrayPP<T> add(T val)
{
t = java.util.Arrays.copyOf(t, t.length + 1);
t[t.length - 1] = val;
return this;
}
In principle you can't easily create arrays of a generic type (or type variable).
If you have a class object, you can use reflection, or if you have an example array, the methods in the java.util.Arrays class to create a (longer/shorter) copy. But it is not elegant either way.
The ArrayList class internally simply uses an Object[] to store its elements, and converts only on get/set/add/toArray.
What would your class do better than ArrayList?
Edit:
I would recommend either simply delegate to an ArraysList, or do the implementation like ArrayList does, using an Object[] internally, and converting on output where necessary.
If you really want to have an array of the right type internally, it is possible - but it gets ugly, as I said.
The add method is still the easiest case:
/**
* Appends a value to the end of the array
* #param val the value to be appended
* #return the resulting array.
*/
public ArrayPP add(T val)
{
T[] temp = Arrays.copyOf(t, t.length+1);
temp[t.length] = val;
t = temp;
return this;
}
When you want to add in the middle or remove, you'll have to combine this with your arraycopy.
Is there some reason the built-it List<T> class(es) can't do what you need? As in:
String[] theArray = {"a", "b", "c"};
List<String> theList = Arrays.asList(theArray);
public ArrayPP(T[] array)
componentClass = array.getClass().getComponentClass();
T[] newArray(int length)
return Array.newInstance(componentClass, length)