Deleting and Inserting Elements in Array [duplicate] - java

This question already has answers here:
How to remove specific element from an array [duplicate]
(6 answers)
Closed 8 years ago.
public class Example {
public static void main(String [] args) {
String [] wombology;
wombology = new String[3];
wombology[0] = "History of Wombology";
wombology[1] = "Why Wombology";
wombology[2] = "Wombology and Me";
Random book = new Random(System.currentTimeMillis());
Scanner choice = new Scanner(System.in);
String yourChoice;
do {
System.out.println("Press enter for random book");
yourChoice = choice.nextLine();
if(yourChoice.equals("")) {
System.out.println(wombology[randomizer.nextInt(3)]);
System.out.println();
}
if(yourChoice == "EXIT") {
break;
}
} while(!yourChoice.equals("EXIT"));
}
}
How could I take out a "book" from the array once chosen randomly?
How could I put back in said "book" later back into the array?
Example: "History of Wombology" is randomly chosen and is taken out.
The next random selection should NOT include "History of Wombology" until it is put back in.
Meaning only "Why Wombology" and "Wombology and Me" should be the only possible choices.

I'm assuming that this is homework and an ArrayList is not possible. And I don't want to give a full, detailed answer.
One option might be to create a parallel array, boolean isCheckedOut[], and track your books there.

You need to manage the array yourself. That means you need to know the real size of the array and the filled size. This is because once the array is created the size cannot change.
If you delete an object from the array you need to shift the adjacent elements towards that position.
For example, your array looks like this:
[A|B|C|D|E|F]
allocatedArraySize = 6
currentSize = 6
If you delete C which is at position 2 then you must shift D, E, F to the left. You could also make the last position null.
[A|B|D|E|F|null]
allocatedArraySize = 6
currentSize = 5
To insert, simply use this:
// Check Array is not full.
if(currentSize != allocatedArraySize)
{
// Then add your object to the last position in the array.
array[currentSize] = obj;
// Increment the index.
currentSize++;
}
else
{
// Don't allow insertion.
// Or create a new-bigger-array;
// then copy all elements of the full array into it.
}

You have to "define" an action for "taking out a book" on the technical level. I can image two possibilities for this
setting the array content at the specific position to null
setting the array content at the specific position to an empty string
As the title of most books consists of one or more letters, the empty string-proposal seems also to be valid.
The second task (putting a book back into the array) can be handled in a similar way. Here you have to find an empty place (an array position with an empty string/null as content) and assign the name of the book to it.
Concerning the randomizer and not allowing already removed books: you can use the aforementioned condition to rerun the randomizer, i.e until an non-empty string/not-null element is found in the array. If you found one, it is a valid choice. But beware, if you removed all books, the randomizer would never stop running (because it finds only invalid choices and hence never returns). Here you can use an additional check condition: if the array only consists of empty strings/ null values, it is not required to run the randomizer.
Hope that helps...

Related

How do array's in java work and what is a data type of the class mean? [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 3 years ago.
Improve this question
Please can you explain to me if we want to add an element to a the end of a preexisting array how is it properly done.
I am having difficulty understanding the Littler class specifically the add method.
I understand that "Puppy[] temp = new Puppy[this.puppies.length + 1];"
We have a new array that is one greater in length than the puppies array (instance variable). "temp[i] = this.puppies[i];" assigns all the elements from the puppies array to the temp based on the indexes.
My confusion lies with line: temp[this.puppies.length] = puppy;
1.) What exactly is happening here?
In my mind I think that we are reassigning the last index position of this.puppies.length to the puppy parameter.
2.) Will that +1 (one size bigger) that was made, the extra index of the temp array on the line
"Puppy[] temp = new Puppy[this.puppies.length + 1];"
remain blank?
3.) Does "this.puppies = temp;" represent a shallow copy?
4.) What is this process called of making a bigger array and adding an object, do we have to do it every time (create an array one bigger).
5.) What happens if we don't, is there a situation where we don't have to make one bigger, or need a temp array? (I am just confused as to why we need it).
6.) What does an object of the class type mean? What does "private Puppy[] puppies;" mean exactly?
7.) Please can you help me decipher this code so I can understand. Especially with a hypothetical example if this.values.length was an array of a size of 5 elements (index 0-4).
//Class where add actions taking place
public class Litter {
private Puppy[] puppies;
public Litter() {
this.puppies = new Puppy[0];
}
public void add(Puppy puppy) {
Puppy[] temp = new Puppy[this.puppies.length + 1];
for (int i = 0; i < puppies.length; i++) {
temp[i] = this.puppies[i];
}
temp[this.puppies.length] = puppy;
this.puppies = temp;
}
}
First and foremost - arrays indices are 0 based. If you have an array of size 10, the valid array indices are from 0 to 9.
temp[this.puppies.length] = puppy
This stores the reference to some Puppy object (puppy) as the last element of the array. (since the length of temp is puppies.length + 1)
Will that +1 (one size bigger) that was made, the extra index of the temp array on the line [..] remain blank
No. The above assignment was made to the last element as arrays use 0-based indexing.
Does "this.puppies = temp;" represent a shallow copy?
No new object is created. After the assignment, both variables, this.puppies and the Puppy array (temp), point to the same object on the heap.
What is this process called of making a bigger array and adding an object, do we have to do it every time (create an array one bigger).
There is no general name for this. It is done here to add a new element to the array. Generally, to avoid this (often), a new array of double the size would be created.
What happens if we don't, is there a situation where we don't have to make one bigger, or need a temp array? (I am just confused as to why we need it).
Since arrays cannot be resized, you have to create a bigger array if you want to add a new object.
What does an object of the class type mean? What does "private Puppy[] puppies;" mean exactly?
puppies is an object that holds an array of Puppy objects.
Please can you help me decipher this code so I can understand. Especially with a hypothetical example if this.values.length was an array of a size of 5 elements (index 0-4).
This method is to add a new Puppy to the existing ones. Since arrays cannot be resized dynamically, it creates a new array(temp) and adds all the existing puppies. To accommodate a new Puppy, the created array size is one greater than the existing puppies. Then, it adds the passed Puppy instance as the last element of the array. The last line this.puppies = temp assigns the reference of the created array to the instance variable that points the puppies array.

Randomly pick elements from an array

This is a part of creating a matching game with graphical components. I need to code a class method named randomOrder. I should be able to randomly choose which pictures to be used and I need to place them randomly on the board (for now the board is a 4x4).
I want a method that randomly moves around the elements in an array. For this I wrote
public class Tools {
public static void randomOrder(Object[] f){
Object[] a = new Object[8];
}
}
The only thing I got from the hint is the following:
"Use a temporary array inside the method and take one element at a time from the original array and place it in the temporary array. If the array-position is taken, then you need to randomize a new position. When all the elements are placed, you can copy the temporary array to the original."
I don't understand how to use the hint. I feel this is so complicated that I can't even formulate a proper question.
Can someone translate the hint to me in a more understandable
question?
Is my start okay?
I'm sorry if the question is bad, I don't know how to make it better. Any suggestions are welcome.
Let me try:
Use a temporary array inside the method
You already did that, although the array a should have the same length as f
take one element at a time from the original array and place it in the temporary array
You iterate over a and for each index you do the following:
Create a random integer between 0 and the size of the array, e.g. for a 4x4 grid your array would have length 16 so the index would be between 0 and 15 (both inclusive).
Get the element at that index from f and place it at the current position in a. Then set that index in f to null.
Example:
//iterate
for( int i = 0; i < a.length; i++ ) {
int random = ...; //create the random number here
Object o = f[random];
while( o == null ) {
//see below
}
a[i] = o;
}
If the array-position is taken, then you need to randomize a new position.
If the element in f already is null then either create a new random number (that's what the text hints at) or increment that index until you hit the end or find a non-null element (probably better from a performance point of view, when you hit the end go back to index 0 for f).
When all the elements are placed, you can copy the temporary array to the original.
When you are done filling a you iterate once again and set the elements in f according to their index in a, i.e.
for( int i = 0; i < a.length; i++ ) {
f[i] = a[i];
}

recursion using a hashmap

I have an array that has the following numbers
int[] arr = {2,4,3,1,5,6,0,7,8,9,10,11,12,13,14,15};
Or any other order for that matter.
I need to make all the possible combinations for the numbers using a recursion but satisfying a condition that the next number clubbed with the present one can only be from specific numbers given by a hashmap:
ex When the recursion takes 1 the next number can be from {0,4,5,2,6} (from the HaspMap),and then if i make 10,the next number can be from {1,4,5} and so on
static HashMap<Integer,Integer[]> possibleSeq = new HashMap<Integer,Integer[] >();
private static void initialize(HashMap<Integer,Integer[]> possibleSeq) {
possibleSeq.put(0,new Integer[]{1,4,5});
possibleSeq.put(1,new Integer[]{0,4,5,2,6});
possibleSeq.put(2,new Integer[]{1,3,5,6,7});
possibleSeq.put(3,new Integer[]{2,6,7});
possibleSeq.put(4,new Integer[]{0,1,5,8,9});
possibleSeq.put(5,new Integer[]{0,1,2,4,6,8,9,10});
possibleSeq.put(6,new Integer[]{1,2,3,5,7,9,10,11});
possibleSeq.put(7,new Integer[]{2,3,6,10,11});
possibleSeq.put(8,new Integer[]{9,4,5,12,13});
possibleSeq.put(9,new Integer[]{10,4,5,8,6,12,13,14});
possibleSeq.put(10,new Integer[]{7,6,5,9,11,15,13,14});
possibleSeq.put(11,new Integer[]{6,7,10,14,15});
possibleSeq.put(12,new Integer[]{8,9,13});
possibleSeq.put(13,new Integer[]{8,9,10,12,14});
possibleSeq.put(14,new Integer[]{9,10,11,13,15});
possibleSeq.put(15,new Integer[]{10,11,14});
}
Note: I am required to make all the possible numbers beginning from digit length 1 to 10.
Help!
Try with something like this, for starters:
void findPath(Set paths, Stack path, int[] nextSteps, Set numbersLeft) {
if (numbersLeft.isEmpty()) {
//Done
paths.add(new ArrayList(path));
return;
}
for (int step:nextSteps) {
if (numbersLeft.contains(step)) {
// We can move on
path.push(step);
numbersLeft.remove(step);
findPath(paths, path, possiblePaths.get(step), numbersLeft);
numbersLeft.add(path.pop());
}
}
}
Starting values should be an empty Set, and empty Stack, a nextSteps identical to you initial array, and a set created from your initial array. When this returns, the paths Set should be filled with the possible paths.
I haven't tested this, and there are bugs as well as more elegant solutions.

Trying to get a random element from an array so that I can mark it as "booked"

This is what I have in my method to randomly select a element in my array, however I'm not sure why it isn't working, I feel like I have tried every way of writing it, any ideas.
public static Seat BookSeat(Seat[][] x){
Seat[][] book = new Seat[12][23];
if (x != null){
book = x[(Math.random()*x.length)];
}
return book;
}
The way you explain things makes me think a couple of concepts somehow got crosswired. I am assuming that book is some (2 dimensional) array of Seat objects from which you want to pick a random one. In order to do so, you need to specify a random choice for each dimension of the array:
// this should be declared elsewhere because if it's local to bookSeat it will be lost
// and reinitialized upon each call to bookSeat
Seat[][] book = new Seat[12][23];
// and this is how, after previous declaration, the function will be called
Seat theBookedSeat = bookSeat(book);
// Okay, now we have selected a random seat, mark it as booked, assuming Seat has a
// method called book:
theBookedSeat.book();
// and this is the modified function. Note also that function in Java by convention
// start with a lowercase letter.
public static Seat bookSeat(Seat[][] x){
if (x != null){
// using Random as shown by chm052
Random r = new Random();
// need to pick a random one in each dimension
book = x[r.nextInt(x.length)][r.nextInt(x[0].length)];
}
return book;
}
You should also integrate a test to check whether the selected seat was already booked and repeat the selection:
do {
// need to pick a random one in each dimension
book = x[r.nextInt(x.length)][r.nextInt(x[0].length)];
while (book.isBooked()); // assuming a getter for a boolean indicating
// whether the seat is booked or not
But a full-random selection like this has a couple of disadvantages:
the selection being random, you can repeatedly fall on already booked seats, and the chances that happens increase with the number of already booked seats. But even with few booked seats you could be really unlucky and see the loop spin around tens of times before it hits an unbooked seat.
you should absolutely test whether there are still unbooked seats left before entering the loop or it will spin indefinitely.
Therefore it might be a good idea to implement a smarter selection routine, eg by randomly picking a row and a seat and start searching from there until the first free seat is encountered, but for first steps this one should do just fine.
I hope this is what you wanted to achieve, if not feel free to comment and allow me to correct and adapt.
Floor the number returned by the (Math.random()*x.length) expression.
Math.floor(Math.random()*x.length);
At the moment, you're trying to subscript the array with a floating point number.
The other answer will totally work, but here is another way of doing it using Random.nextInt() if you don't want to have to do all the mathing around:
Random r = new Random();
book = x[r.nextInt(x.length)];
It uses java.util.Random, so make sure you import that if you do this.

How can I optimize this code?

My current project has us using TreeSet and TreeMap in Java, with an input array of 10514 Song elements read in from a text file. Each Song contains a Artist, Title and Lyric fields. The aim of this project is to conduct fast searches on the lyrics using sets and maps.
First, I iterate over the input Song array, accessing the lyrics field and creating a Scanner object to iterate over the lyric words using this code: commonWords is a TreeSet of words that should not be keys, and lyricWords is the overall map of words to Songs.
public void buildSongMap() {
for (Song song:songs) {
//method variables
String currentLyrics= song.getLyrics().toLowerCase();
TreeSet<Song> addToSet=null;
Scanner readIn= new Scanner(currentLyrics);
String word= readIn.next();
while (readIn.hasNext()) {
if (!commonWords.contains(word) && !word.equals("") && word.length()>1) {
if (lyricWords.containsKey(word)) {
addToSet= lyricWords.get(word);
addToSet.add(song);
word=readIn.next();
} else
buildSongSet(word);
} else
word= readIn.next();
}
}
In order to build the songSet, I use this code:
public void buildSongSet(String word) {
TreeSet<Song> songSet= new TreeSet<Song>();
for (Song song:songs) {
//adds song to set
if (song.getLyrics().contains(word)) {
songSet.add(song);
}
}
lyricWords.put(word, songSet);
System.out.println("Word added "+word);
}
Now, since buildSongSet is called from inside a loop, creating the map executes in N^2 time. When the input array is 4 songs, searches run very fast, but when using the full array of 10514 elements, it can take over 15+ min to build the map on a 2.4GHz machine with 6 GiB RAM. What can I do to make this code more efficient? Unfortunately, reducing the input data is not an option.
It looks like your buildSongSet is doing redundant work. Your block:
if (lyricWords.containsKey(word)) {
addToSet= lyricWords.get(word);
addToSet.add(song);
word=readIn.next();
}
adds a song to an existing set. So, when you find a word you don't know about, just add one song to it. Change buildSongSet to:
public void buildSongSet(String word, Song firstSongWithWord) {
TreeSet<Song> songSet= new TreeSet<Song>();
songSet.add(firstSongWithWord);
lyricWords.put(word, songSet);
System.out.println("Word added "+word);
}
the remaining songs left to be iterated will then be added to that songset from the first block of code if they contain that word. I think that should work.
EDIT just saw this was homework... so removed the HashSet recommendations..
Ok.. so suppose you have these Songs in order with lyrics:
Song 1 - foo
Song 2 - foo bar
Song 3 - foo bar baz
Song 1 will see that foo does not contain lyricWords, so it will call buildSongSet and create a set for foo. It will add itself into the set containing foo.
Song 2 will see that foo is in lyricWords, and add itself to the set. It will see bar is not in the set, and create a set and add itself. It doesn't need to traverse previous songs since the first time the word was seen was in Song 2.
Song 3 follows the same logic.
Another thing you can try doing to optimize your code is to figure out a way to not process duplicate words in the lyrics. if your lyrics are foo foo foo foo bar bar bar foo bar then you're going to be doing a lot of unnecessary checks.
EDIT also see rsp's answer - additional speedups there, but the big speedup is getting rid of the inner loop - glad it's down to 15 secs now.
The whole buildSongSet() method is not needed imho, as your main loop already adds songs to the collection by word. The only thing you are missing is the addition of a set for a new word, something like:
if (lyricWords.containsKey(word)) {
addToSet= lyricWords.get(word);
} else {
addToSet = new TreeSet();
lyricWords.put(word, addToSet);
}
addToSet.add(song);
One issue that you did not tackle is that songs end up being added to the set multiple times, for every occurence of the word in the song.
Another issue is that in the case that a song contains just 1 word, you do not add it at all! It is always better to check the condition first:
String word = null;
while (readIn.hasNext()) {
word = readIn.next();
Your condition is doing one check too many (the empty string has length < 1), and swapping the checks can speed up things too:
if (word.length() > 1 && !commonWords.contains(word)) {
Please, try change TreeSet to HashSet. I can't see where you obtain the benefits of TreeSet.
if you want a very extensible, easy way of solving this with performance in the order of a few millisecons. Consider lucene http://lucene.apache.org/
refer to my answer here for example of how to index and search
How do I index and search text files in Lucene 3.0.2?

Categories