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?
Related
There is a storage unit, with has a capacity for N items. Initially this unit is empty.
The space is arranged in a linear manner, i.e. one beside the other in a line.
Each storage space has a number, increasing till N.
When someone drops their package, it is assigned the first available space. The packages could also be picked up, in this case the space becomes vacant.
Example: If the total capacity was 4. and 1 and 2 are full the third person to come in will be assigned the space 3. If 1, 2 and 3 were full and the 2nd space becomes vacant, the next person to come will be assigned the space 2.
The packages they drop have 2 unique properties, assigned for immediate identification. First they are color coded based on their content and second they are assigned a unique identification number(UIN).
What we want is to query the system:
When the input is color, show all the UIN associated with this color.
When the input is color, show all the numbers where these packages are placed(storage space number).
Show where an item with a given UIN is placed, i.e. storage space number.
I would like to know how which Data Structures to use for this case, so that the system works as efficiently as possible?
And I am not given which of these operations os most frequent, which means I will have to optimise for all the cases.
Please take a note, even though the query process is not directly asking for storage space number, but when an item is removed from the store it is removed by querying from the storage space number.
You have mentioned three queries that you want to make. Let's handle them one by one.
I cannot think of a single Data Structure that can help you with all three queries at the same time. So I'm going to give an answer that has three Data Structures and you will have to maintain all the three DS's state to keep the application running properly. Consider that as the cost of getting a respectably fast performance from your application for the desired functionality.
When the input is color, show all the UIN associated with this color.
Use a HashMap that maps Color to a Set of UIN. Whenever an item:
is added - See if the color is present in the HashMap. If yes, add this UIN to the set else create a new entry with a new set and add the UIN then.
is removed - Find the set for this color and remove this UIN from the set. If the set is now empty, you may remove this entry altogether.
When the input is color, show all the numbers where these packages are placed.
Maintain a HashMap that maps UIN to the number where an incoming package is placed. From the HashMap that we created in the previous case, you can get the list of all UINs associated with the given Color. Then using this HashMap you can get the number for each UIN which is present in the set for that Color.
So now, when a package is to be added, you will have to add the entry to previous HashMap in the specific Color bucket and to this HashMap as well. On removing, you will have to .Remove() the entry from here.
Finally,
Show where an item with a given UIN is placed.
If you have done the previous, you already have the HashMap mapping UINs to numbers. This problem is only a sub-problem of the previous one.
The third DS, as I mentioned at the top, will be a Min-Heap of ints. The heap will be initialized with the first N integers at the start. Then, as the packages will come, the heap will be polled. The number returned will represent the storage space where this package is to be put. If the storage unit is full, the heap will be empty. Whenever a package will be removed, its number will be added back to the heap. Since it is a min-heap, the minimum number will bubble up to the top, satisfying your case that when 4 and 2 are empty, the next space to be filled will be 4.
Let's do a Big O analysis of this solution for completion.
Time for initialization: of this setup will be O(N) because we will have to initialize a heap of N. The other two HashMaps will be empty to begin with and therefore will incur no time cost.
Time for adding a package: will include time to get a number and then make appropriate entries in the HashMaps. To get a number from heap will take O(Log N) time at max. Addition of entries in HashMaps will be O(1). Hence a worst case overall time of O(Log N).
Time for removing a package: will also be O(Log N) at worst because the time to remove from the HashMaps will be O(1) only while, the time to add the freed number back to min-heap will be upper bounded by O(Log N).
This smells of homework or really bad management.
Either way, I have decided to do a version of this where you care most about query speed but don't care about memory or a little extra overhead to inserts and deletes. That's not to say that I think that I'm going to be burning memory like crazy or taking forever to insert and delete, just that I'm focusing most on queries.
Tl;DR - to solve your problem, I use a PriorityQueue, an Array, a HashMap, and an ArrayListMultimap (from guava, a common external library), each one to solve a different problem.
The following section is working code that walks through a few simple inserts, queries, and deletes. This next bit isn't actually Java, since I chopped out most of the imports, class declaration, etc. Also, it references another class called 'Packg'. That's just a simple data structure which you should be able to figure out just from the calls made to it.
Explanation is below the code
import com.google.common.collect.ArrayListMultimap;
private PriorityQueue<Integer> openSlots;
private Packg[] currentPackages;
Map<Long, Packg> currentPackageMap;
private ArrayListMultimap<String, Packg> currentColorMap;
private Object $outsideCall;
public CrazyDataStructure(int howManyPackagesPossible) {
$outsideCall = new Object();
this.currentPackages = new Packg[howManyPackagesPossible];
openSlots = new PriorityQueue<>();
IntStream.range(0, howManyPackagesPossible).forEach(i -> openSlots.add(i));//populate the open slots priority queue
currentPackageMap = new HashMap<>();
currentColorMap = ArrayListMultimap.create();
}
/*
* args[0] = integer, maximum # of packages
*/
public static void main(String[] args)
{
int howManyPackagesPossible = Integer.parseInt(args[0]);
CrazyDataStructure cds = new CrazyDataStructure(howManyPackagesPossible);
cds.addPackage(new Packg(12345, "blue"));
cds.addPackage(new Packg(12346, "yellow"));
cds.addPackage(new Packg(12347, "orange"));
cds.addPackage(new Packg(12348, "blue"));
System.out.println(cds.getSlotsForColor("blue"));//should be a list of {0,3}
System.out.println(cds.getSlotForUIN(12346));//should be 1 (0-indexed, remember)
System.out.println(cds.getSlotsForColor("orange"));//should be a list of {2}
System.out.println(cds.removePackage(2));//should be the orange one
cds.addPackage(new Packg(12349, "green"));
System.out.println(cds.getSlotForUIN(12349));//should be 2, since that's open
}
public int addPackage(Packg packg)
{
synchronized($outsideCall)
{
int result = openSlots.poll();
packg.setSlot(result);
currentPackages[result] = packg;
currentPackageMap.put(packg.getUIN(), packg);
currentColorMap.put(packg.getColor(), packg);
return result;
}
}
public Packg removePackage(int slot)
{
synchronized($outsideCall)
{
if(currentPackages[slot] == null)
return null;
else
{
Packg packg = currentPackages[slot];
currentColorMap.remove(packg.getColor(), packg);
currentPackageMap.remove(packg.getUIN());
currentPackages[slot] = null;
openSlots.add(slot);//return slot to priority queue
return packg;
}
}
}
public List<Packg> getUINsForColor(String color)
{
synchronized($outsideCall)
{
return currentColorMap.get(color);
}
}
public List<Integer> getSlotsForColor(String color)
{
synchronized($outsideCall)
{
return currentColorMap.get(color).stream().map(packg -> packg.getSlot()).collect(Collectors.toList());
}
}
public int getSlotForUIN(long uin)
{
synchronized($outsideCall)
{
if(currentPackageMap.containsKey(uin))
return currentPackageMap.get(uin).getSlot();
else
return -1;
}
}
I use 4 different data structures in my class.
PriorityQueue I use the priority queue to keep track of all the open slots. It's log(n) for inserts and constant for removals, so that shouldn't be too bad. Memory-wise, it's not particularly efficient, but it's also linear, so that won't be too bad.
Array I use a regular Array to track by slot #. This is linear for memory, and constant for insert and delete. If you needed more flexibility in the number of slots you could have, you might have to switch this out for an ArrayList or something, but then you'd have to find a better way to keep track of 'empty' slots.
HashMap ah, the HashMap, the golden child of BigO complexity. In return for some memory overhead and an annoying capital letter 'M', it's an awesome data structure. Insertions are reasonable, and queries are constant. I use it to map between the UIDs and the slot for a Packg.
ArrayListMultimap the only data structure I use that's not plain Java. This one comes from Guava (Google, basically), and it's just a nice little shortcut to writing your own Map of Lists. Also, it plays nicely with nulls, and that's a bonus to me. This one is probably the least efficient of all the data structures, but it's also the one that handles the hardest task, so... can't blame it. this one allows us to grab the list of Packg's by color, in constant time relative to the number of slots and in linear time relative to the number of Packg objects it returns.
When you have this many data structures, it makes inserts and deletes a little cumbersome, but those methods should still be pretty straight-forward. If some parts of the code don't make sense, I'll be happy to explain more (by adding comments in the code), but I think it should be mostly fine as-is.
Query 3: Use a hash map, key is UIN, value is object (storage space number,color) (and any more information of the package). Cost is O(1) to query, insert or delete. Space is O(k), with k is the current number of UINs.
Query 1 and 2 : Use hash map + multiple link lists
Hash map, key is color, value is pointer(or reference in Java) to link list of corresponding UINs for that color.
Each link list contains UINs.
For query 1: ask hash map, then return corresponding link list. Cost is O(k1) where k1 is the number of UINs for query color. Space is O(m+k1), where m is the number of unique color.
For query 2: do query 1, then apply query 3. Cost is O(k1) where k1 is the number of UINs for query color. Space is O(m+k1), where m is the number of unique color.
To Insert: given color, number and UIN, insert in hash map of query 3 an object (num,color); hash(color) to go to corresponding link list and insert UIN.
To Delete: given UIN, ask query 3 for color, then ask query 1 to delete UIN in link list. Then delete UIN in hash map of query 3.
Bonus: To manage to storage space, the situation is the same as memory management in OS: read more
This is very simple to do with SegmentTree.
Just store a position in each place and query min it will match with vacant place, when you capture a place just assign 0 to this place.
Package information possible store in separate array.
Initiall it have following values:
1 2 3 4
After capturing it will looks following:
0 2 3 4
After capturing one more it will looks following:
0 0 3 4
After capturing one more it will looks following:
0 0 0 4
After cleanup 2 it will looks follwong:
0 2 0 4
After capturing one more it will looks following:
0 0 0 4
ans so on.
If you have segment tree to fetch min on range it possible to done in O(LogN) for each operation.
Here my implementation in C#, this is easy to translate to C++ of Java.
public class SegmentTree
{
private int Mid;
private int[] t;
public SegmentTree(int capacity)
{
this.Mid = 1;
while (Mid <= capacity) Mid *= 2;
this.t = new int[Mid + Mid];
for (int i = Mid; i < this.t.Length; i++) this.t[i] = int.MaxValue;
for (int i = 1; i <= capacity; i++) this.t[Mid + i] = i;
for (int i = Mid - 1; i > 0; i--) t[i] = Math.Min(t[i + i], t[i + i + 1]);
}
public int Capture()
{
int answer = this.t[1];
if (answer == int.MaxValue)
{
throw new Exception("Empty space not found.");
}
this.Update(answer, int.MaxValue);
return answer;
}
public void Erase(int index)
{
this.Update(index, index);
}
private void Update(int i, int value)
{
t[i + Mid] = value;
for (i = (i + Mid) >> 1; i >= 1; i = (i >> 1))
t[i] = Math.Min(t[i + i], t[i + i + 1]);
}
}
Here example of usages:
int n = 4;
var st = new SegmentTree(n);
Console.WriteLine(st.Capture());
Console.WriteLine(st.Capture());
Console.WriteLine(st.Capture());
st.Erase(2);
Console.WriteLine(st.Capture());
Console.WriteLine(st.Capture());
For getting the storage space number I used a min heap approach, PriorityQueue. This works in O(log n) time, removal and insertion both.
I used 2 BiMaps, self-created data structures, for storing the mapping between UIN, color and storage space number. These BiMaps used internally a HashMap and an array of size N.
In first BiMap(BiMap1), a HashMap<color, Set<StorageSpace>> stores the mapping of color to the list of storage spaces's. And a String array String[] colorSpace which stores the color at the storage space index.
In the Second BiMap(BiMap2), a HashMap<UIN, storageSpace> stores the mapping between UIN and storageSpace. And a string arrayString[] uinSpace` stores the UIN at the storage space index.
Querying is straight forward with this approach:
When the input is color, show all the UIN associated with this color.
Get the List of storage spaces from BiMap1, for these spaces use the array in BiMap2 to get the corresponding UIN's.
When the input is color, show all the numbers where these packages are placed(storage space number). Use BiMap1's HashMap to get the list.
Show where an item with a given UIN is placed, i.e. storage space number. Use BiMap2 to get the values from the HashMap.
Now when we are given a storage space to remove, both the BiMaps have to be updated. In BiMap1 get the entry from the array, get the corersponding Set, and remove the space number from this set. From BiMap2 get the UIN from the array, remove it and also remove it from the HashMap.
For both the BiMaps the removal and the insert operations are O(1). And the Min heap works in O(Log n), hence the total time complexity is O(Log N)
Me and my friend is working with a program that should be handling customers. The thing is that we need to check if a telephone number is used on more than one customer. The code works fine until we reach 4 customers with the same number... It then prints out the last customer with that number twice! We can't figure out what is wrong with it, so would be lovely if you could throw a quick eye on our code :)
//CASE 10: LISTA TELEFONNUMMER SOM FLER ÄN EN KUND HAR
public static void listaTelNr() {
String KtelefonNr;
String Knamn;
for(int y=0;y<TelefonNrLista.size();y++){
for(int x=y+1;x<TelefonNrLista.size();x++){
if (TelefonNrLista.get(y).getTelNr().equals(TelefonNrLista.get(x).getTelNr())){
KtelefonNr=TelefonNrLista.get(y).getTelNr();
Knamn= TelefonNrLista.get(y).getKundNamn();
SammaTelNr nySammaTelNr=new SammaTelNr(KtelefonNr,Knamn);
SammaTelNrLista.add(nySammaTelNr);
KtelefonNr=TelefonNrLista.get(x).getTelNr();
Knamn= TelefonNrLista.get(x).getKundNamn();
SammaTelNr nySammaTelNr2=new SammaTelNr(KtelefonNr,Knamn);
SammaTelNrLista.add(nySammaTelNr2);
}
}
}
for(int y=0;y<SammaTelNrLista.size();y++){
for(int x=y+1;x<SammaTelNrLista.size();x++){
if (SammaTelNrLista.get(y).getKundNamn().equals(SammaTelNrLista.get(x).getKundNamn())){
SammaTelNrLista.remove(x);
}
}
}
for(int i=0;i<SammaTelNrLista.size();i++){
System.out.println(SammaTelNrLista.get(i));
}
}
Store your number-customer relation in a map and your code will be much cleaner and faster.
// Map<phoneNumber, customerList>
Map<String, List<Customer>> phoneNumberCustomersMap = new ...
Your issue is most likely related to the fact that you are trying to remove elements from the list SammaTelNrLista in a for loop. To safely remove from a collection you should use an Iterator.
Also, you could make you solution a bit more efficient if you remove the filtering step. When adding elements to the SammaTelNrLista list you can check if the name is already in the list. And only add it if it's not there. You could use a map for this.
In your first loop: if the names are not equal and the numbers are equal then add the number to a HashSet. After that loop over the entries of the hash set and print them.
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...
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.
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.