I'm trying to, given some ArrayList of Integers, create all the permutations of that list. I want to store each permutation (an ArrayList itself) in a bigger ArrayList of ArrayLists. I can find the permutations and print each to the console without an issue. I haven't found a way to successfully add them to a list. My current attempt is shown below.
//myList is a field that I need to use elsewhere
//a is the ArrayList of Integers
//initially, n is a.size()
private static void perm2(ArrayList<ArrayList<Integer>> myList,
ArrayList<Integer> a, int n)
{
for (int i = 0; i < n; i++)
{
swap(a, i, n-1);
perm2(where, a, n-1);
swap(a, i, n-1);
}
if (n == 1)
{
System.out.println(a.toString());
myList.add(a);
return;
}
}
Here is the output given [0, 1, 2]:
[1, 2, 0]
[2, 1, 0]
[2, 0, 1]
[0, 2, 1]
[1, 0, 2]
[0, 1, 2]
[[0, 1, 2], [0, 1, 2], [0, 1, 2], [0, 1, 2], [0, 1, 2], [0, 1, 2]]
The print code is sending the right thing to the console, so why isn't it adding the right thing immediately after? If this isn't a good way to go about it, which direction should I look to? Ultimately, these are indices to retrieve data from a list in every order.
Thanks in advance.
I should note that the input list can be of arbitrary length, within reasonable computing capabilities.
EDIT: oversight on my part. Here's the swap code:
private static void swap(ArrayList<Integer> list, int a, int b)
{
T temp = list.get(a);
list.set(a, list.get(b));
list.set(b, temp);
}
You always store the same list in the list of lists. Then you swap its elements and store it again. So you end up with N references to the same list. You need to make a copy of the list before storing it in the list of lists:
myArray.add(new ArrayList<>(a));
You haven't shown us swap, but I assume it is modifying the list in place. The list of lists then contains multiple references to the same underlying list, which is in the final permuted state. Basically, you've put a mutable object into a list and then changed it, while expecting it to be in the state it was in when you first added it to the list.
One way to fix this is to make a defensive copy of the list at the time you add it:
myArray.add(new ArrayList<Integer>(a));
(Also, you call your variable myArray and say, "add them to an array", but myArray is a List and you are adding things to a list. I was a bit confused when I first read your question. You shouldn't refer to a list as an array.)
Each time when you call 'add' method on myArray, elements of 'a' are not copied. myArray will hold a refernece to 'a' only. Since the reference is always the same, the latest state of 'a' element will be printed.
Try to print the content of myArray right after myArray.add(a) to see what I mean.
You do need to create a new instance of ArrayList to avoid this problem
Related
I'm trying to generate an array of 5 non-repeating integers in Java, but there are still repeats when I run it. Here's my code so far:
public int[] generateCode(){
code[0] = (int)Math.round(Math.random()*8+1); // initialize first number so it won't be compared against
for(int i=1; i<code.length; i++){
code[i] = (int)Math.round(Math.random()*8)+1;
for(int j=0; j<i; j++){
while(code[i]==code[j]){
code[i] = (int)Math.round(Math.random()*8)+1;
}
} // end inner for loop
} // end outer for loop
return code;
} // end generateCode method
Any help is very much appreciated!
So, your for-loop is checking for repeated characters, BUT each time you generate a new value (in the while-loop) you're not checking to see if the value exits before j.
There are a number of possible ways you might address this issue, I prefer ones which uses Collections.shuffle, but assuming that you can't use features like Arrays, Collections, List, Set or possibly even streams, we need to work with what we have, arrays.
Since you have a small range of acceptable values which need to fit into an even smaller range, a simple solution might be to generate a "master" list of allowed values and randomly select a value from the master list, tracking which values you've already picked.
Sounds more complicated then it actually is, for example...
public int[] generateCode() {
int[] masterValues = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
int[] codes = new int[5];
Random rnd = new Random();
int index = 0;
while (index < codes.length) {
int lookupIndex = 0;
do {
lookupIndex = rnd.nextInt(masterValues.length);
} while (masterValues[lookupIndex] == 0);
codes[index] = masterValues[lookupIndex];
masterValues[lookupIndex] = 0;
index++;
}
return codes;
}
This creates a "master" list of values. It then randomly calculates a "lookup" index, checks to see if the value in the master list is 0 or not, if not, it assigns it to the next index in the codes array and sets the value in the master list to 0, otherwise it generates a new random index and tries again. This all repeats till it fills the codes array
So doing something like...
System.out.println(Arrays.toString(generateCode()));
System.out.println(Arrays.toString(generateCode()));
System.out.println(Arrays.toString(generateCode()));
System.out.println(Arrays.toString(generateCode()));
could print (because it's "random")...
[8, 1, 4, 7, 5]
[9, 6, 2, 1, 8]
[6, 5, 9, 4, 7]
[2, 5, 3, 1, 4]
There are much easier ways to do this. Using a Set<Integer> would be one. Here is another.
List<Integer> list = new ArrayList<>(List.of(1,2,3,4,5,6,7,8));
Collections.shuffle(list);
System.out.println(list.subList(0,5));
prints something like
[4, 5, 8, 2, 1]
As was pointed out to me, you may not be allowed to use or know about collections. But I would recommend you at least make a helper method to check for duplicates to reduce the clutter. Something like the following:
public boolean contains(int[] arr, int n) {
for (int v : arr) {
if (v == n) {
return true;
}
}
return false;
}
Then you can keep checking the current value to be false before you add it. Once it works it also lets you focus on other aspects of your code.
I have an integer array of size 4. I am adding elements to it via the add method. This is as an unsorted array. I am sorting it via the sort method shown in the code below. The sort method places the smallest number in the position a[0]. When I try to add elements after I call the sort method I always get a return value of 0. Is there a way around this?
import java.util.Arrays;
public class Scrap {
private static int[] array = new int[4];
private static int i = 0;
public static void main(String[] args) {
Scrap pq = new Scrap();
pq.add(4);
pq.insert(3);
pq.add(5);
pq.sort();// smallest to largest sort method.
// System.out.println(array[0]);
pq.insert(1);
pq.sort();
int test = pq.Minimum();
System.out.println("The smallest element of the array is " + test);
pq.sort();
}
//
public void add(int input) {
insert(input);
}
// Method to insert number into the array.
public void insert(int input) {
array[i] = input;
i++;
}
// Finding smallest number of the array.
public int Minimum() {
int a = array[0];
return a;
}
// Sorts the array from smallest to largest integer
public void sort() {
int first, temp;
for (int i = array.length - 1; i > 0; i--) {
first = 0;
for (int j = 1; j <= 1; j++) {
if (array[j] > array[first])
first = j;
}
temp = array[first];
array[first] = array[i];
array[i] = temp;
}
}
public int remove() {
return delete();
}
public int delete() {
return remove();
}
// Method to convert the array into a string for output
}
The problem in a nutshell:
You start with an array of length 4.
At this point the array contains 4 zeros, that is: [0, 0, 0, 0]
You add 4, 3, and 5. These operations update the content of the array to [4, 3, 5, 0].
You sort the array. This should change the content of the array to [0, 3, 4, 5]. In fact it changes to [0, 5, 3, 4], which means your implementation of sort is clearly broken.
You probably didn't expect the 0 value to move. You can fix this by sorting only the first 3 values. (And, of course, you should also fix your implementation of sort.)
Then when you insert 1, the program updates the value at index 3, so the content changes to [0, 5, 3, 1].
If you implement the fix I suggested above, and sort only the first size elements, then the content after the first call to sort should become [3, 4, 5, 0], and the content after the insert 1 should become [3, 4, 5, 1]. And when you sort that again, the content should become [1, 3, 4, 5] and the smallest value will be 1 as expected, instead of 0.
More concretely:
First of all, change private static int i = 0; to private int size = 0;. The name i is extremely inappropriate here, and will surely confuse you. size is appropriate. It also doesn't make sense to make it static, so I suggest to drop that keyword.
Fix the implementation of sort. There are many basic sorting algorithms that are easy to implement. In the implementation, instead of going until array.size, go until size. Do you see the difference? size is the field in Scrap, essentially it's the number of elements you added using the add or insert methods.
Some cleaning up would be good too:
Delete the add method and rename insert to add.
Delete the remove and delete methods. They are not used, and you will get a stack overflow if you try to use them as they are now (the methods call each other, forever)
Look at the content of the array after each step in the program.
After Scrap pq is created, this is the content of its array:
[0, 0, 0, 0]
Then a couple of modifications:
pq.add(4);
pq.insert(3);
pq.add(5);
The content at this point:
[4, 3, 5, 0]
So far so good.
Then you sort it:
pq.sort();
The content at this point:
[0, 5, 3, 4]
Ouch. The sort implementation doesn't work very well, does it. But let's ignore that for now. Next step:
pq.insert(1);
The content at this point:
[0, 5, 3, 1]
None of this behavior makes sense, probably this is not how you intended the program to work. Review the program, verify the content after each step. Do not proceed to the next step until the current step is working correctly.
I am assuming that you will be using a correct sort method (because, this is not correct, you can use Arrays.sort). But still with a correct sort, there is a logical problem in your code.
At the beginning, the array contains all 0s. After adding the first 3 int, when you call the sort method, the array contains the values in following order:
0,3,4,5
Note that, the value of i is not changed. At this state the value of i is 3. So when you insert 1, the new values become
0,3,4,1
So after sorting again, the values of arrays become
0,1,3,4
So obviously the minimum will retrun 0
I don't think that is the most effective way to sort an array. It is possible to do this with just 1 for loop. Try this to sort your array from smallest to largest.
int temp;
for(int i=0;i<array.length-1;i++){
if(array[i]>array[i+1]){
temp=array[i];
array[i]=array[i+1];
array[i+1]=temp;
i=-1;
}
}
This is what I coded myself and I understand everything what is done here:
import java.util.Arrays;
public class Decision{
public static void main (String[]args){
int[] myArray = {1,8,3,0,2};
for(int i=0; i<myArray.length-1; i++){
if(myArray[i]<myArray[i+1]){
}
else{
int temp=myArray[i];
myArray[i]=myArray[i+1];
myArray[i+1]=temp;
}
System.out.println(Arrays.toString(myArray));
}
}
}
Output: [1, 3, 0, 2, 8]
So we first check if the first value in the array is smaller than the next one. If yes, then don't do anything. If not, then swap both.
The problem with this sort algorithm is that it won't swap as example the first value with the third one, or the second with the fifth, etc.
I realized this sort works perfectly if we add a second for-loop that repeats the for-loop in my code:
for(int n=myArray.length; n>1; n=n-1){
...
}
I also realized this kind of sort is called bubble sort, but please explain me the important role of this for-loop, I'm sad I cannot understand what it does at all? : /
In all honesty I'm a bit confused about your question. Normally I'd recommend adding diagnostics printouts, but you already have one. As you can see, doing only one pass can at most swap an item with the one next to it. There's no way you can fully sort the array this way, because once you process one element at [i], your algorithm of course can't move that element anywhere else. So if it's not in its final correct position after that one pass, it'll never get there. In particular, a given element can only be moved to the left at most 1 position per pass. The worst case of this is if the input is sorted in decreasing order before going in.
When you add an outer loop doing multiple passes, it sorts the array a little bit more each time, until finally it's sorted. Doing myArray.length - 1 passes guarantees that even the worst-case elements get a chance to be "moved" through the entire array to their correct position, because in the worst case input it guarantees that you'll be able to move an element left through the entire array (in an array of length n it takes n-1 moves to get the element in the last position into the first position -- if this doesn't click, draw it on paper and count).
I mean, there is an important skill missing from your toolset that you really ought to learn, which is that you need to get used to visualizing what your code does. There are a few ways to do this:
Research the algorithm you are implementing. The linked wiki article on bubble sort pretty clearly explains the algorithm in the step-by-step section.
With some experience it will make sense in your head.
Work things out on paper.
Trace through things line-by-line in your debugger.
Add temporary trace print-outs to your programs.
And of course, sometimes experimenting with algorithms by breaking them and observing the changes.
You went with #5 and #6, you just need to learn how to interpret the information. Here is a working version of your sort, for example (ignoring other potential code improvements, I am certain other answers here will help you along those line) with one extra print added to separate the passes in the output:
public static void main (String[]args){
int[] myArray = {1,8,3,0,2};
for(int n=myArray.length; n>1; n=n-1){
System.out.println("Outer loop: " + n);
for(int i=0; i<myArray.length-1; i++){
if(myArray[i]<myArray[i+1]){
}
else{
int temp=myArray[i];
myArray[i]=myArray[i+1];
myArray[i+1]=temp;
}
System.out.println(Arrays.toString(myArray));
}
}
}
This outputs:
Outer loop: 5
[1, 8, 3, 0, 2]
[1, 3, 8, 0, 2]
[1, 3, 0, 8, 2]
[1, 3, 0, 2, 8]
Outer loop: 4
[1, 3, 0, 2, 8]
[1, 0, 3, 2, 8]
[1, 0, 2, 3, 8]
[1, 0, 2, 3, 8]
Outer loop: 3
[0, 1, 2, 3, 8]
[0, 1, 2, 3, 8]
[0, 1, 2, 3, 8]
[0, 1, 2, 3, 8]
Outer loop: 2
[0, 1, 2, 3, 8]
[0, 1, 2, 3, 8]
[0, 1, 2, 3, 8]
[0, 1, 2, 3, 8]
As you can see, after the first pass it's not fully sorted. The second pass is a bit closer. The third pass completes it in this case. It's the 0 that's holding things up in this case: The 0 has to move left 3 positions, and so you must complete at least 3 passes.
For an even clearer picture try that ideone example with the worst case input of [8, 3, 2, 1, 0].
Assume the worst case for this algorithm, an array sorted in reverse order and see what happens with one loop
4 3 2 1 0 original array
3 4 2 1 0 after one swap
3 2 4 1 0 after two swaps
3 2 1 4 0 after three swaps
3 2 1 0 4 after the complete loop
You see that only the largest element is now in the right place, all the rest is still in reverse order. After a second pass the second largest element will be in the correct place as well and so on.
Note that the passes after the first do not have to go over the full array (but it does not hurt) because more and more elements will already have reached their final position.
Instead of adding the 2nd loop you could also say
boolean change = true;
while (change) {
change = false;
...
if (a[i] > a[i + 1]) { // write it like this and you don't need an else
change = true;
// swap
}
...
}
Both work, because the maximum number of passes needed to sort the array is n - 1. For the worst case, an array sorted descending instead of ascending, the elements will wander to the end like water bubbles to the top of the water. On the first iteration the first element will end up in the last position, on the 2nd iteration the originally 2nd element (now first) will travel up to the 2nd last position and so on. So you can see that you need only n-1 iterations, because on the (n-1)th iteration the originally 2nd last element (now the first) will end up in 2nd position and the originally last element (now the first) is already sorted correctly.
You can also notice, that on each iteration (at least) one more element at the end of the array ends up in its correct position, so you can decrease the max for the inner loop on each iteration.
I can only seem to find answers about last/first element in a list or that you can get a specific item etc.
Lets say I have a list of 100 elements, and I want to return the last 40 elements. How do I do that? I tried doing this but it gave me one element..
Post last40posts = posts.get(posts.size() -40);
Do use the method sub list
List<Post> myLastPosts = posts.subList(posts.size()-40, posts.size());
(To complete Ankit Malpani answer)
If 40 is provided by our lovely users, then you will have to restrict it to the list size:
posts.subList(posts.size()-Math.min(posts.size(),40), posts.size())
Another way to show it:
#Test
public void should_extract_last_n_entries() {
List<String> myList = Arrays.asList("0","1","2","3","4");
int myListSize = myList.size();
log.info(myList.subList(myListSize,myListSize).toString()); // output : []
log.info(myList.subList(myListSize-2,myListSize).toString()); // output : [3, 4]
log.info(myList.subList(myListSize-5,myListSize).toString()); // output : [0, 1, 2, 3, 4]
int lastNEntries = 50; // now use user provided int
log.info(myList.subList(myListSize-Math.min(myListSize,lastNEntries),myListSize).toString());
// output : [0, 1, 2, 3, 4]
// log.info(myList.subList(myListSize-lastNEntries,myListSize).toString());
// ouch IndexOutOfBoundsException: fromIndex = -45
}
Your code will give you only a single element.
You need to use subList method like:
posts.subList(posts.size()-40, posts.size())
suppose I have arraylist of integers...is there a way that I can generate a random permutation/arrangement of the elements in the arraylist
so if the list is {1,2,3,4,5,6}
calling some method randomPermute() would change it to something random like
{1,3,2,6,5,4}
Collections.shuffle() does the job:
public static void shuffle(List<?> list) -
Randomly permutes the specified list using a default source of randomness. All permutations occur with approximately equal likelihood.
http://download.oracle.com/javase/6/docs/api/java/util/Collections.html#shuffle(java.util.List)
For example
ArrayList<Integer>anArrayList = new ArrayList<Integer>();
anArrayList.add(1);
anArrayList.add(2);
anArrayList.add(3);
anArrayList.add(4);
anArrayList.add(5);
System.out.println(anArrayList);
Collections.shuffle(anArrayList);
System.out.println(anArrayList);
Sample Output
[1, 2, 3, 4, 5]
[3, 5, 1, 2, 4]
You can use the Knuth shuffle: go through the positions 1 through n−1, and for each position i swap the element currently there with an arbitrarily chosen element from positions i through n, inclusive.
Edit: The answer by hooch is better. :)
A simple example:
ArrayList<MyObject> myObjects = new ArrayList<MyObject>();
//code -- load myObjects...
Collections.shuffle(myObjects);