Related
Here is my code
import java.util.*;
public class ArrayExample {
public static void main(String[] args) {
Integer arr[] = {5,4,3,2,15,8,9};
List<Integer> list = Arrays.asList(arr);
Collections.sort(list);
System.out.println(list);
list.add(6);// here I am adding 6 to my array.
System.out.println(list);
// Here I should get output as [2,3,4,5,6,8,9,15]
}
}
You can't because this declaration :
List<Integer> list = Arrays.asList(arr);
From documentation :
Arrays.asList Returns a fixed-size list backed by the specified array. (Changes to the returned list "write through" to the array.)
This method acts as bridge between array-based and collection-based
APIs, in combination with Collection.toArray(). The returned list is
serializable and implements RandomAccess.
for that you can't add to this list, even if you try to remove list.remove(index); this not work.
so to solve your problem you can use :
List<Integer> list = new ArrayList<>();//declare the list
for(Integer i : arr){
list.add(i);//add element by element to the list
}
Or simply you can use :
List<Integer> list = new ArrayList<>(Arrays.asList(arr));
//----------------------------------^------------------^
If you want the array to stay sorted, you will have to sort it after each insert.
However, using a binary search, you could also find the index i where the item should be inserted and insert it there using list.add(i,6). Which would be more efficient.
No you cannot add, as you are using Arrays.asList(arr);
List<Integer> list = Arrays.asList(arr);
asList returning a fixed-size list, you cannot add any element in that, once the list is formed.
You may get java.lang.UnsupportedOperationException
[2, 3, 4, 5, 8, 9, 15]
Exception in thread "main" java.lang.UnsupportedOperationException
at java.util.AbstractList.add(AbstractList.java:148)
at java.util.AbstractList.add(AbstractList.java:108)
at Test.main(Test.java:14)
You can add an element without using a list by using 2 arrays: a source array src and a destination array dest. The destination array will have one more element than the source one. You simply need to copy all the elements of the source array to the destination, and add your new element. Depends on different requirement of your post title & your post body, I added 2 solutions:
Solution 1
This solution add an element to your array AFTER sorting the array, as mentioned in the post title. But please notice that the element added is located at the tail of the new array.
Integer src[] = { 5, 4, 3, 2, 15, 8, 9 };
Integer dest[] = new Integer[src.length + 1];
Arrays.sort(src);
System.out.println(Arrays.toString(src));
// [2, 3, 4, 5, 8, 9, 15]
System.arraycopy(src, 0, dest, 0, src.length);
dest[src.length] = 6;
System.out.println(Arrays.toString(dest));
// [2, 3, 4, 5, 8, 9, 15, 6]
// ^
Solution 2
This solution add an element to your array BEFORE sorting the array. It contains the expected array as mentioned in your code comment in the post body.
Integer src[] = { 5, 4, 3, 2, 15, 8, 9 };
Integer dest[] = new Integer[src.length + 1];
System.arraycopy(src, 0, dest, 0, src.length);
dest[src.length] = 6;
Arrays.sort(dest);
System.out.println(Arrays.toString(dest));
// [2, 3, 4, 5, 6, 8, 9, 15]
// ^
See also:
Sorting methods in Arrays (Java Platform SE 8) - Oracle Help Center
System#arraycopy(Object, int, Object, int, int)
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'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
I'm a student teaching myself about Comparators and I came across odd behavior that I'm having trouble understanding. I'm attempting to shuffle an array using Arrays.sort and a Random object, however when I seed the Random object the shuffle either reverses the array or does nothing. Not seeding the Random object leads to it being shuffled as expected.
No seed:
Integer[] integers = new Integer[]{1, 2, 3, 4, 5, 6};
Arrays.sort(integers, new Comparator<T>() {
#Override
public int compare(T o1, T o2) {
return new Random().nextInt();
}
});
>>> [4, 3, 5, 2, 1, 6]
Seed:
Integer[] integers = new Integer[]{1, 2, 3, 4, 5, 6};
Arrays.sort(integers, new Comparator<T>() {
#Override
public int compare(T o1, T o2) {
return new Random(System.currentTimeMillis()).nextInt();
}
});
>>> [1, 2, 3, 4, 5, 6] or [6, 5, 4, 3, 2, 1]
Could someone help me understand this behavior?
I do understand this is terrible code. These are just toy examples to help me get familiar with the mechanics of Comparators. I'm more interested in the resulting behavior regardless.
Seeding controls the random number stream you generate. If you seed with the same seed, you'll get the same sequence every time. You're seeding here with the same number each time (because it won't take even 1ms to do the sort), so the nextInt() will always return the same value. Thus it will always return the same sort. Since your data is sorted coming in, that causes it to stay in the same order.
If you want to seed correctly, create the Random object once, and call it rather than recreating with the same seed each time.
Much of your Random objects created will get the same seed since the code runs fast.
For example, you could throw in a brief Thread.sleep(10) in your Comparator. Or you could run:
for (int i = 0; i < 7; i++) {
System.out.println("" + new Random(System.currentTimeMillis()).nextInt());
}
You do understand why this is terrible code, right? You would only create one Random object once, and then use the same one in your Comparator, right?
Even if you use only a single Random object you will still get unexpected behavior with a random Comparator. From the documentation from Comparator.
The implementor must ensure that sgn(compare(x, y)) == -sgn(compare(y,
x)) for all x and y.
By not following that implementation requirement you will get undefined behavior.
You can see a visualization of what the resulting shuffles look like here: http://bost.ocks.org/mike/shuffle/compare.html
(Note: the shuffles there are using Javascript not Java, but the issue applies to Java as well.)
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);