add something to an array based on order - java

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];
}

Related

Getting the nth element of a set several times in Java

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.

Returning a linked list containing keys from another Linked List

I have the following problem. I have a linked list or positional list containing objects called Entry. Each entry stores a key and a value pair. I want to make another linked list to grab from that list just the keys. I have come up with a method to do so,however for some reason they order in which I added them is not represented when I print the key list. I have the following two methods:
public PositionalList1<K> keySet() //I prnted position by position while adding and it worked. I also tested addAfter with positionalList1 class and it worked
{
PositionInterface<Entry> iterator = map.first(); //gets first position in the Entry List
PositionInterface<K> first = keyList.addFirst((K)iterator.getData().getKey()); //adds to list containing just keys the key from the Entry list(getData is just a method that returns whatever object is stored at the node, in this case a Entry Object)
iterator = map.after(iterator); //go to next node in Entry list
for(int i=0;i<size-1;i++) //get rest of keys
{
PositionInterface<K> p = keyList.addAfter(first,(K)iterator.getData().getKey());
iterator = map.after(iterator);
}
return keyList;
}
public void printKeySet(PositionalList1 list) //print key list
{
PositionInterface p = list.first();
for(int i=0; i<list.size();i++)
{
System.out.println("Key : " + p.getData());
p = list.after(p);
}
}
The keySet() method returns the list containing only keys, while the printKeySet takes the result of KeySet() and prints the entire key list. I have tested this using the following main program:
OrderedMapL<Integer,String> map2 = new OrderedMapL<Integer,String>();
map2.put(2,"A");//adds (2,A)
map2.put(5,"B");//adds(5,B)
map2.put(1,"C");//adds(1,C)
map2.put(4,"D");//adds(4,D)
map2.put(3,"E");//adds(3,E)
map2.remove(2); //removes (2,A)
This resulted in a ordered list of (1,C) (2,A) .. etc and the entries themselves print fine in this order. The problem arises when calling the following:
PositionalList1<Integer> keyList = map2.keySet();
map2.printKeySet(keyList);
For some reason the keys are printing in the order: 1,5,4,3 instead of 1,3,4,5 and I have no idea why. Any help would be appreciated.
The problem is with this line:
PositionInterface<K> p = keyList.addAfter(first,(K)iterator.getData().getKey());
You shouldn't add after first. That is why You get wrong order.
If the keys are 1, 3, 4, 5 then You are adding it like this:
Add 1 as first element 1
Add 3 after first element 1 3
Add 4 after first element 1 4 3
Add 5 after first element 1 5 4 3
It is because You are adding it after the first element.
If I understand Your code correctly You should change it like this:
// I suspect that #addFirst method returns added list element
PositionInterface<K> last = keyList.addFirst((K) iterator.getData().getKey());
iterator = map.after(iterator);
for(int i = 0; i < size - 1; i++)
{
// I suspect that #addAfter method returns added list element
PositionInterface<K> last = keyList.addAfter(last, (K) iterator.getData().getKey());
iterator = map.after(iterator);
}

IndexOutOfBoundException using java.util.Vector

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

Remove elements from ArrayList

I have to remove elements from ArrayList, but I have not gone through it. Elements which I have to remove are also available in ArrayList. In short, I have to remove one Array List from another Array List. e.g. Suppose
ArrayList<String> arr1= new ArrayList<String>();
ArrayList<String> arr2 = new ArrayList<String>();
arr1.add("1");
arr1.add("2");
arr1.add("3");
arr2.add("2");
arr2.add("4");
Now, I have to remove elements which are in arr2 from arr1. So, that I have final answer as 1 and 3.
What needs to be done?
Read Remove Common Elements in Two Lists Java
Use below code
List<String> resultArrayList = new ArrayList<String>(arr1);
resultArrayList.removeAll(arr2);
Or can be done by
arr1.removeAll(arr2)
After SO comments
I used the following code
ArrayList<String> arr1= new ArrayList<String>();
ArrayList<String> arr2 = new ArrayList<String>();
arr1.add("1");
arr1.add("2");
arr1.add("3");
arr2.add("2");
arr2.add("4");
System.out.println("Before removing---");
System.out.println("Array1 : " + arr1);
System.out.println("Array2 : " + arr2);
System.out.println("Removing common ---");
List<String> resultArrayList = new ArrayList<String>(arr1);
resultArrayList.removeAll(arr2);
System.out.println(resultArrayList);
and getting output as
Before removing---
Array1 : [1, 2, 3]
Array2 : [2, 4]
Removing common ---
[1, 3]
So what is not working at your side?
Read more about How do you remove the overlapping contents of one List from another List?
Take new arr as final sorted array
for(int i=0;i<arr1.size();i++)
{
for(int j=0;j<arr2.size();j++)
if(!arr1.get(i).contains(arr2.get(j)))
{
arr.add(arr1.get(i));
}
}
You can use removeAll() function
/**
* Removes from this list all of its elements that are contained in the
* specified collection.
*
* #param c collection containing elements to be removed from this list
* #return {#code true} if this list changed as a result of the call
* #throws ClassCastException if the class of an element of this list
* is incompatible with the specified collection
* (optional)
* #throws NullPointerException if this list contains a null element and the
* specified collection does not permit null elements
* (optional),
* or if the specified collection is null
* #see Collection#contains(Object)
*/
public boolean removeAll(Collection<?> c) {
return batchRemove(c, false);
}
To remove duplicate of one from other use this
int arr1Size = arr2.size();
int arr2Size = arr2.size();
for (int i = 0; i < arr1Size; i++)
{
for (int j = 0; j < arr2Size; j++)
{
if (arr1.get(i).contains(arr2.get(j)))
{
arr1.remove(i);
}
}
}
System.out.print(arr1);
Ok to make things clear:
if your list is composed of basic elements such as String etc
all you need to do is use
list2.removeAll(list1);
assuming that isnt the case meaning you created a list from custum objects - the above method wont work, that is due to the nature of the item comparison.
it uses the object.equals method which by default checks if this is the same instance of the object in the other list (which it probably isnt)
so in order for this to work you need to overwrite the custom object equals method.
example - test if 2 contacts are the same based on phone number:
public boolean equals(Object o)
{
if (o==null)
{
return false;
}
if (o.getClass()!=this.getClass())
{
return false;
}
Contact c=(Contact)o;
if (c.get_phoneNumber().equals(get_phoneNumber()))
{
return true;
}
return false;
}
now if you use
list2.removeAll(list1);
it will compare the items based on the desired attribute (in the example based on phone number) and will work as planned.

How to combine 2 Vectors in a JList?

Vector<String> totalProducts = Products.getProductNames();
Vector<String> selectedProducts = Products.getSelectedProductNames();
The selectedProducts vector is a subvector of totalProducts (meaning that selectedProducts contains one, more or all of the elements from totalProducts). What I want is to combine these two vectors and make a single JList, which contains all the elements from totalProducts, and with the elements of selectedProducts already selected.
What I tried:
Vector<Integer> indices = new Vector<Integer>();
JList prdList = new JList(totalProducts);
for(int i = 0; i < totalProducts.size(); i++)
{
for(String name : selectedProducts)
{
if(totalProducts.contains(name)) indices.add(i);
}
}
Object [] objIndices = indices.toArray();
//... Cast from Object [] to int [] ....
prdList.setSelectedIndices(intIndices);
...but this selects all the elements in the final JList.
Previously I tried:
JList prdList = new JList(totalProducts);
for(String tName : totalProducts)
{
for(String sName : selectedProducts)
{
if(totalProducts.contains(sName)) prdList.setSelectedValue(sName, false);
}
}
...but this one selected only the last element from the selectedProducts.
Can you please help me to do it right?
Your attempt that selects all items does so because you're iterating over each item, and if any item from the selectedProducts list is in the total list, adds the iteration item's index to the final selection list. Try changing your loop to something like this:
for(int i = 0; i < totalProducts.size(); i++)
{
String name = totalProducts.get(i);
if(selectedProducts.contains(name)) indices.add(i);
}
in debugging your first attempt (which looks like it should work, what was the contents of your intIndices array? because that looks like it should work, presuming your array conversion works.
however, since selectedproducts is guaranteed to be less items than total, you might want to iterate over that instead?
List<Integer> indices = new ArrayList<Integer>(selectedProducts.size());
for(String name : selectedProducts)
{
int index = totalProducts.indexOf(name);
if (index != -1)
indices.add(index);
}
although, since indexOf is a linear search through a list, it probably doesn't make much of a difference either way.
as for your second attempt, the ListSelectionModel has methods for adding a selected index (addSelectionInterval(int index0, int index1))
, you're using the one that sets (overwrites) the selection.
see http://download.oracle.com/javase/6/docs/api/javax/swing/ListSelectionModel.html
aside: you might want to use List<> instead of Vector<>, as vector has a lot of unecessary synchronization overhead. Unless you need the synchronization....
edit fixed copy+paste of add(i) with add(index)

Categories