Moving elements around in a ArrayList - java

I'm trying to swap elements around in an ArrayList, but I don't know how to get the position of the items I want to sawp around because it's not a 2D array. I'm trying to use
Collections.swap(list, 3, 3-1);
But it doesn't work.
List<Integer> list = new ArrayList<Integer>();
for (int i = 0; i < 16; i++) {
list.add(i);
}
//System.out.println(list); //[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
Collections.shuffle(list);
// System.out.println(list); //[11, 5, 10, 9, 7, 0, 6, 1, 3, 14, 2, 4, 15, 13, 12, 8]
int[][] a2 = new int[4][4];
for (int i = 0; i < 4; i++) {
for (int j = 0; j< 4; j++) {
a2[i][j] = list.get(i*4 + j);
// System.out.println(Arrays.deepToString(a2)); //[[11, 5, 10, 9], [7, 0, 6, 1], [3, 14, 2, 4], [15, 13, 12, 8]]
}
//System.out.println(Arrays.deepToString(a2)); //[[11, 5, 10, 9], [7, 0, 6, 1], [3, 14, 2, 4], [15, 13, 12, 8]]
// System.out.println();
}
for (int[] row : a2) {
System.out.print("[");
for (int i : row)
System.out.printf("%4d", i);
System.out.println("]");
}
Collections.swap(list, 3, 3-1); //this is where im stuck
}
I view this as a matrix, thats why I want to swap. How do co-ordinates in ArrayList work?
The output when you run this is:
[ 10 15 12 7]
[ 0 9 2 6]
[ 4 3 1 11]
[ 5 8 14 13]
I want to swap the elements up, down and sideways.

I'm not very sure I understand your question, but as for the remark:
"I don't know how to get the position of the items"
use ArrayList.add(int index, E element), this way you'll know that the element you just added is at poistion "index"

To swap element at i,j with element at k,l you could do
Collections.swap(list, i*4+j, k*4+l);

I'm assuming
You want to work with a matrix. That 4x4 square of numbers. Right?
You want to swap elements between positions in the matrix
You are using two ways of representation: List<Integer> and a int[][]
How to swap with array
Position (i, j) in your matrix is simply a2[i][j] so swaping between (i, j) and (k, l) is:
int aux = a2[k][l];
a2[k][l] = a[i][j]; // move value at first point to second point
a2[i][j] = aux; // move value at second poin tof irst point
How to swap with list
Position (i, j) in your list (because of the way you saved it) is 4*i+j. So the indexes for the same points in the list are (as #aioobe said):
4*i+j
4*k+l
So you'd need to do this:
Collections.swap(list, 4*i+j, 4*k+l);
where 4 is the size of each row.
Changing the approach
If what you want is simply using that list for shuffling (because all the rest of the handling doesn't need a list but a matrix) I suggest: use only List for that shuffling and forgetting. How?
// at this point you only have a matrix: your `int a2[][]`
// and the List will only exist for the shuffling
// lets say that WIDTH HEIGHT exist and are int constants
List<Integer> tempList = new ArrayList<Integer>(WIDTH*HEIGHT);
for (int i=0; i<HEIGHT; i++)
for (int j=0; j<WIDTH; j++)
list.add(a2[i][i]);
// now your integers are in the list and you can shuffle them
Collections.shuffle(tempList);
// now give the numbers back to the matrix (as on your previous code)
for (int i=0; i<HEIGHT; i++)
for (int j=0; j<WIDTH; j++)
a2[i][i] = list.get(i*WIDTH+j);
// and you can forget your tempList
Even better you could make this a method:
private void shuffle(int[][] matrix, int width, int height) {
List<Integer> tempList = new ArrayList<Integer>(width*height);
for (int i=0; i<height; i++)
for (int j=0; j<width; j++)
list.add(matrix[i][i]);
// now your integers are in the list and you can shuffle them
Collections.shuffle(tempList);
// now give the numbers back to the matrix (as on your previous code)
for (int i=0; i<height; i++)
for (int j=0; j<width; j++)
matrix[i][i] = tempList.get(i*width+j);
}
Notice that tempList exists only when method executes.
Even better: create two methods for converting from matrix representation to list and viceversa. That way you can use them in other places (and your code is more readable). By example, you could refactor you code to initialize the ordered list and calling that method to convert it into an int matrix.
private List<Integer> toList(int[][] matrix, int width, int height) {
List<Integer> list = new ArrayList<Integer>(width*height);
for (int i=0; i<height; i++)
for (int j=0; j<width; j++)
list.add(matrix[i][i]);
return list;
}
private int[][] toMatrix(List<Integer> list, int width, int height) {
// now give the numbers back to the matrix (as on your previous code)
int[][] result = new int[height][];
for (int i=0; i<height; i++) {
result[i] = new int[width];
for (int j=0; j<width; j++)
result[i][i] = list.get(i*width+j);
}
return result;
}
private int[][] shuffle(int[][] matrix, int width, int height) {
List<Integer> tempList = toList(matrix, width, height);
// now your integers are in the list and you can shuffle them
Collections.shuffle(tempList);
return toMatrix(tempList, width, height);
}
Notice toMatrix and shuffle methods now return a new matrix!!
Bottomline
It's useful to see your code as small blocks of code each one doing some clearly defined task. The you can maintain the abstractions in your code and create methods (or even classes ;-) with useful names as I tried to do. Of course, as all things it comes with practice. Good luck.
Disclaimer
It's not usual to write all the solution but in order to learn it can be useful. So it is. Hope it's useful!

Related

Comparing two arrays and then making another array with common elements (and no duplicates)

Hi, I'm a newbie to Java and I was doing this lab assignment where we compare elements of two arrays to get the common elements. I am stuck on how to get rid of duplicates.
My current code is giving me the output [3, 0, 5, 6, 5, 0, 9, 0] and the desired output of common is [3, 5, 6, 9, 0, 0, 0, 0].
Also, since I am not that experienced, please do not post professional ways to do the problem or "experienced" answers to my question, as that would not help me at all :D.
Thanks!
public static void main (String[] args) {
int[] a1 = {3, 8, 5, 6, 5, 8, 9, 2};
int[] a2 = {5, 15, 4, 6, 7, 3, 9, 11, 9, 3, 12, 13, 14, 9, 5, 3, 13};
int[] common = new int[a1.length];
System.out.println("Exercise 3: ");
findCommon(a1,a2,common);
}
public static void findCommon(int[] a1, int[]a2, int[] common) {
int num = 0;
for (int i = 0; i < common.length; i++)
{
for (int j = 0; j < a2.length; j++)
{
if (a1[i] == a2[j]) // loops through every index of j, while keeping i at one index
num = a1[i];
for (int k = 0; k < common.length; k++) // makes sure there are no duplicates in common
{
if (num != common[k])
common[i] = num;
}
}
}
for (int elements : common)
System.out.print(elements + " ");
}
You should look into using Sets to do this kind of thing, but since this is an exercise I've provided a solution with some comments along the way in the code.
Basically you should break the problem down into pieces, each of which is its own method. That way you will have an easier time getting it straight.
arrayIntersect(int[], int[])
This method's job is to create an array from two arrays. The resulting array must have unique elements that are present in both arrays.
You can do n. 1 with a helper method (mentioned below).
inArray(int, int[])
This method returns true if an array contains the given element, false otherwise.
Example
public static void main (String[] args) {
int[] a1 = {3, 8, 5, 6, 5, 8, 9, 2};
int[] a2 = {5, 15, 4, 6, 7, 3, 9, 11, 9, 3, 12, 13, 14, 9, 5, 3, 13};
int[] a3 = arrayIntersect(a1, a2);
for (int a : a3) {
System.out.println(a);
}
}
private static int[] arrayIntersect(int[] a1, int[] a2) {
int[] intersect = new int[Math.min(a1.length, a2.length)];
int curIndex = 0;
for (int x : a1) {
if (inArray(x, a2) && !inArray(x, intersect)) {
intersect[curIndex] = x;
curIndex++;
}
}
// resize intersect array to not include unused indexes
int[] tmp = intersect;
intersect = new int[curIndex];
for (int i = 0; i < intersect.length; i++) {
intersect[i] = tmp[i];
}
return intersect;
}
private static boolean inArray(int element, int[] array) {
boolean result = false;
for (int a : array) {
if (element == a) {
result = true;
break;
}
}
return result;
}
You are very close to the correct anwser, but the for loop for (int k = 0; k < common.length; k++) is being executed for every element of a2. So, when an value exist for a1 but doesn't exist for a2, you are putting the old value of num at the common array. If you look at the elements printed, you will see that every time that an element just exist in a1, the element repeat.
The result of the code is
3 3 5 6 5 5 9 9
You put the right identation, but forgot the curly brackets. If you put the curly brackets at the if (a1[i] == a2[j]), this will be the result:
3 0 5 6 5 0 9 0
But why these 0 are there? Because when you create an int array in java, all elements start with the value of 0. And you are putting the common elements at the same position of the presence of this elements in the a1 array. You can correct this by populating the int array with an invalid number and them ignorin it. At this code, I assumed that -1 is an invalid value.
public static void findCommon(int[] a1, int[] a2, int[] common) {
int num = 0;
for (int i = 0; i < common.length; i++) {
common[i] = -1;
}
for (int i = 0; i < common.length; i++) {
for (int j = 0; j < a2.length; j++) {
if (a1[i] == a2[j]) { // loops through every index of j, while keeping i at one index
num = a1[i];
for (int k = 0; k < common.length; k++) // makes sure there are
// no duplicates in common
{
if (num != common[k])
common[i] = num;
}
}
}
}
for (int elements : common) {
if (elements != -1)
System.out.print(elements + " ");
}
}
If you see, At the if (elements != -1) I didn't put the curly brackets but it worked. If you don't put the curly brackets, it will just execute the next command.

Array Processing (stretching) Method

I'm looking for a hint on how to solve this or where I am going wrong.
The question is as follows: Write a static method named stretch that accepts an array of integers as a parameter and returns a new array twice as large as the original, replacing every integer from the original array with a pair of integers, each half the original. If a number in the original array is odd, then the first number in the new pair should be one higher than the second so that the sum equals the original number. For example, if a variable named list refers to an array storing the values {18, 7, 4, 24, 11}, the call of stretch(list) should return a new array containing {9, 9, 4, 3, 2, 2, 12, 12, 6, 5}. (The number 18 is stretched into the pair 9, 9, the number 7 is stretched into 4, 3, the number 4 is stretched into 2, 2, the number 24 is stretched into 12, 12 and the number 11 is stretched into 6, 5.)
Test your code with the following class:
import java.util.*;
public class TestStretch {
public static void main(String[] args) {
int[] list = {18, 7, 4, 14, 11};
int[] list2 = stretch(list);
System.out.println(Arrays.toString(list)); // [18, 7, 4, 24, 11]
System.out.println(Arrays.toString(list2)); // [9, 9, 4, 3, 2, 2, 7, 7, 6, 5]
}
// your code goes here
}
This is currently what I have, but it is not quite working correctly... I have a feeling it is how i'm using int i and int j, but i'm not sure what to do to fix it so that it works as intended.
import java.util.*;
public class TestStretch {
public static void main(String[] args) {
int[] list = {18, 7, 4, 14, 11};
int[] list2 = stretch(list);
System.out.println(Arrays.toString(list)); // [18, 7, 4, 24, 11]
System.out.println(Arrays.toString(list2)); // [9, 9, 4, 3, 2, 2, 7, 7, 6, 5]
}
public static int[] stretch(int[] array){
int length = array.length;
int[] newArray = new int[array.length*2];
for(int i = 0; i< length; i=i+2){
int j = 0;
if(array[i] % 2 == 0){
newArray[i] = (array[j]/2);
newArray[i+1] = newArray[i];
j++;
} else{
newArray[i] = (array[j]/2);
newArray[i+1] = (newArray[i] + 1);
j++;
}
}
return newArray;
}
}
The output I get is:
[18, 7, 4, 14, 11]
[9, 9, 9, 9, 9, 10, 0, 0, 0, 0]
Instead of:
[18, 7, 4, 24, 11]
[9, 9, 4, 3, 2, 2, 7, 7, 6, 5]
There are a couple of mistakes:
The loop iterates only until half of the array, skipping elements by 2
The value of j is reset to 0 in each iteration
Also, the algorithm can be simplified:
For each index i in the input, you want to set in the destination at position 2 * i and 2 * i + 1.
The second value to set is simply the original value divided by 2, with integer truncation
The first value to set is the same as the second, +1 if the division by 2 leaves a remainder
With the above issues corrected, and the implementation simplified:
int[] newArray = new int[array.length * 2];
for (int i = 0; i < array.length; i++) {
newArray[2 * i] = array[i] / 2 + array[i] % 2;
newArray[2 * i + 1] = array[i] / 2;
}
return newArray;
First of all, if you are looping to the old array's length, don't increment i by 2.
If i increases by 1 each time, we need to figure out how to map the old array's index i to the new array's index. It is quite simple: the new array's indices are just i*2 and i*2+1.
Now j seems redundant because it always holds the same value as i, so you can remove that.
This is the full code:
int length = array.length;
int[] newArray = new int[array.length*2];
for(int i = 0; i< length; i++){
if(array[i] % 2 == 0){
newArray[i*2] = (array[i]/2);
newArray[i*2+1] = newArray[i*2];
} else{
newArray[i*2] = (array[i]/2);
newArray[i*2+1] = (newArray[i*2] + 1);
}
}
return newArray;
Three mistakes:
j should be initialized outside the for-loop
we should use j to record the new value into the new array
we should increment j upon every iteration in 2 - and we should increment i only by 1 (since we're using j to insert two item while we use i to iterate the original array):
int j = 0;
for(int i = 0; i< length; i++){
if(array[i] % 2 == 0){
newArray[j] = newArray[j+1] = array[i]/2;
} else{
newArray[j] = array[i]/2 + 1;
newArray[j+1] = array[i]/2;
}
j += 2;
}
Note: giving a variable that holds an array the name "list" might create confusion!
for(int i = 0; i< length; i=i+2){
length is the length of the original array, so you iterate only over half of the values because you increase i by 2 each step.
if(array[i] % 2 == 0){
This should be
if(array[j] % 2 == 0){
And because you define j within your for-loop, array[j] always returns 18. Oh and you set the second element of the tuple to be the higher one while your comment in the code says the contrary should take place.
So a fixed version of your method would look like this:
public static int[] stretch(int[] array){
int length = array.length;
int[] newArray = new int[array.length*2];
int j = 0;
for(int i = 0; i< newArray.length; i=i+2){
if(array[j] % 2 == 0){
newArray[i] = (array[j]/2);
newArray[i+1] = newArray[i];
} else{
newArray[i+1] = (array[j]/2);
newArray[i] = (newArray[i+1] + 1);
}
j++;
}
return newArray;
}
Avoiding duplicate code:
public static int[] stretch(int[] array){
int[] newArray = new int[array.length*2];
int j = 0;
for(int i = 0; i< newArray.length; i=i+2){
int val = array[j];
newArray[i] = (val/2);
newArray[i+1] = newArray[i];
if(val % 2 != 0){
newArray[i]++;
}
j++;
}
return newArray;
}
Or using fancy streams:
public static int[] stretch(int[] array){
return Arrays.stream(array)
.flatMap(elem -> {
int half = elem / 2;
int otherHalf = half;
if (elem % 2 != 0) {
half++;
}
return IntStream.of(half, otherHalf);
}).toArray();
}
}

Evenly distribute lists into sublists in Java

I want to evenly distribute a list into a given number of sublists.
For example, I have a list with elements 1 to 10 and I want 3 lists. These should look like:
SL1 -> {1, 2, 3, 4}
SL2 -> {5, 6, 7}
SL3 -> {8, 9, 10}
Important: What each list contains is not relevant, i.e. SL1 could have {1, 5, 7, 10}. The most important thing is that there are 2 lists with size 3 and 1 list with size 4.
I have tried several things, including the Iterables.partition but that won't help.
The only thing I've come up with that works is:
public Iterable<List<Integer>> distributeEvenlyQueryListIntoLists(final LinkedList<Integer> bigList, final Integer numberOfSublists) {
List<List<Integer>> result = new ArrayList<>();
// Creates as many lists as needed
for (int i = 0; i < numberOfSublists; i++) {
result.add(new ArrayList<>());
}
while (bigList.iterator().hasNext()) {
for (int i = 0; i < numberOfSublists; i++) {
if (!bigList.iterator().hasNext()) {
break;
}
result.get(i).add(bigList.poll());
}
}
return result;
}
The passed bigList does not have to be a LinkedList, it can be any Iterable.
I especially hate the first loop where I create the sublists.
Thanks!
Just distribute them in a round-robin pattern:
public <T> List<List<T>> partition(Iterable<T> iterable, int partitions){
List<List<T>> result = new ArrayList<>(partitions);
for(int i = 0; i < partitions; i++)
result.add(new ArrayList<>());
Iterator<T> iterator = iterable.iterator()
for(int i = 0; iterator.hasNext(); i++)
result.get(i % partitions).add(iterator.next());
return result;
}
A sample run with this code:
List<String> l = Stream.iterate(0, i->i + 1).limit(25).map(i->Integer.toString(i)).collect(Collectors.toList());
System.out.println(partition(l, 4).toString());
Produces
[[0, 4, 8, 12, 16, 20, 24], [1, 5, 9, 13, 17, 21], [2, 6, 10, 14, 18, 22], [3, 7, 11, 15, 19, 23]]
The basic idea is to add a single element to each list in the result set roundwise. This way it's guaranteed that the difference in the number of elements between two lists never exceeds 1.
As an alternative you could use guavas implementation of Iterables.partition, which takes a slightly different approach.
If you hate creating sublists, that implies you're looking for a fast solution. If you have the original List, and you plan on not altering the original List, consider List.subList().
int subSize = bigList.length() / numSubs;
int numBigSubs = 0; // # of subs that need to be one bigger
if (bigList.length() % numSubs > 0) {
subSize++;
numBigSubs = bigList.length() % numSubs;
}
int from = 0;
int to = subSize;
List<List<Integer>> subList = new ArrayList<List<Integer>>(numSubs);
for (int i = 0; i < numSubs; i++) {
List<Integer> newSub = bigList.subList(from, to);
subList.add (newSub);
from = to;
to += subSize;
if (i >= numBigSubs && numBigSubs > 0) to--;
}
Note: I wrote this without testing - if it fails, I apologize, and hope someone will edit it to work.
Again, the big upside to this is that it should be wicked fast - all the sublists are simply views into the larger one. The downside is that if you change the list, all bets are off.
You can use org.apache.commons.collections4.ListUtils to create equal size sublists.
List<String> bigList = ...
int batchSize = 1000;
List<List<String>> smallerLists = ListUtils.partition(bigList, batchSize);

Java: Array of first n integers

Any shortcut to create a Java array of the first n integers without doing an explicit loop?
In R, it would be
intArray = c(1:n)
(and the resulting vector would be 1,2,...,n).
If you're using java-8, you could do:
int[] arr = IntStream.range(1, n).toArray();
This will create an array containing the integers from [0, n). You can use rangeClosed if you want to include n in the resulting array.
If you want to specify a step, you could iterate and then limit the stream to take the first n elements you want.
int[] arr = IntStream.iterate(0, i ->i + 2).limit(10).toArray(); //[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
Otherwise I guess the simplest way to do is to use a loop and fill the array. You can create a helper method if you want.
static int[] fillArray(int from, int to, int step){
if(to < from || step <= 0)
throw new IllegalArgumentException("to < from or step <= 0");
int[] array = new int[(to-from)/step+1];
for(int i = 0; i < array.length; i++){
array[i] = from;
from += step;
}
return array;
}
...
int[] arr3 = fillArray(0, 10, 3); //[0, 3, 6, 9]
You can adapt this method as your needs to go per example from an upperbound to a lowerbound with a negative step.

frequency of items in int[] as opposed to List<Integer>?

I'm trying to figure out how to get the frequency of items within a list. When I approach this problem I typically, in the past, did:
int occurrences = Collections.frequency(list, 0);
It works when my list is a List<Integer> list. Is there a way to do this if I'm using int[] list? When I try collections, my list gets converted and then my code breaks. I can convert my code if needed, but was wondering, if there was a way to get the frequency from int[] instead.
You can (1) write your own linear-time frequency method, or (2) convert to an array of boxed int types and use Arrays.asList with Collections.frequency.
int[] arr = {1, 2, 3};
Integer[] boxedArr = new Integer[arr.length];
for(int i = 0; i < arr.length; i++)
boxedArr[i] = arr[i];
System.out.println(Collections.frequency(Arrays.asList(boxedArr), 1));
You could create a List from the int[], but otherwise, you just have to write your own.
int[] l = //your data;
List<Integer> list = new List<Integer>();
for(int i : l)
list.add(i);
int o = Collections.frequency(list, 0);
Or Arrays.asList(l); to make it shorter.
int occurrences = Collections.frequency(Arrays.asList(list), 0);
Or if you are against converting it to a list:
int occurrences = 0;
for (int i = 0; i < list.length; i++)
{
if(list[i] == X) // X being your number to check
occurrences++;
}
You can do this way as well.
List<Integer> intList = Arrays.asList(new Integer [] {
2, 3, 4, 5, 6,
2, 3, 4, 5,
2, 3, 4,
2, 3,
2
});
System.out.println(" count " + Collections.frequency(intList, 6));

Categories