iterating through multidimensional ArrayList - java

I am confused regarding iterating through a multidimensional ArrayList .
I saw some topics about it and they seem complicated. in specific the accepted
answer here:
How to iterate through two dimensional ArrayList using iterator?
can it be as in this method? which iterates through the arrayList and copy the value to an array:
private void reassembleArray(int[] array, ArrayList<ArrayList<Integer>> buckets) {
Iterator<ArrayList<Integer>> it = buckets.iterator();
int i = 0;
while (it.hasNext()) {
ArrayList<Integer> intList = it.next();
Iterator<Integer> itInteger = intList.iterator();
while (itInteger.hasNext()) {
array[i] = itInteger.next();
i++;
}
}
}
are there any dangers or side effects for using this simple form?
this is the complete program which is an implementation of a sort algorithm called radix sort.
import java.util.ArrayList;
import java.util.Iterator;
/**
* Radix sort implementation
*/
public class RadixSort {
/**
* Runs the program
*/
public static void main(String[] args) {
int[] array = {315, 418, 591, 260, 533, 58, 976, 938,};
System.out.println("Radix sort implementation");
printArray(array);
sort(array, 3); // 3 is the maximun number of digits in all array elements to sort
printArray(array);
}
/*
* sort array of integers using radix sort algorithm
* #param array The array
* #param n the maximum number of digits in array elements
*/
private void sort(int[] array, int n) {
int digitNumber = 0;
while (digitNumber < n) {
ArrayList<ArrayList<Integer>> buckets = initBuckets();
// store each element in the bucket corresponding to the (digitNumber + 1)th
// digit of that element
for (int i = 0; i < array.length; i++) {
int value = array[i];
int bucket = (value / (int) (Math.pow(10, digitNumber))) % 10;
buckets.get(bucket).add(value);
}
reassembleArray(array, buckets);
digitNumber++;
}
}
/*
* Initialize buckets ArrayList
* #return The buckets ArrayList
*/
private ArrayList<ArrayList<Integer>> initBuckets() {
ArrayList<ArrayList<Integer>> buckets = new ArrayList<ArrayList<Integer>>();
// a bucket for each digit from 0 to 9
for(int i = 0; i < 10; i++) {
buckets.add(new ArrayList<Integer>());
}
return buckets;
}
/*
* Reassemble the array
* #param array The array
* #param buckets The buckets
*/
private void reassembleArray(int[] array,
ArrayList<ArrayList<Integer>> buckets) {
Iterator<ArrayList<Integer>> it = buckets.iterator();
int i = 0;
while (it.hasNext()) {
ArrayList<Integer> intList = it.next();
Iterator<Integer> itInteger = intList.iterator();
while (itInteger.hasNext()) {
array[i] = itInteger.next();
i++;
}
}
}
/*
* Prints an array of integers on a single line
* #param array The array
*/
private void printArray(int[] array) {
System.out.print("array: {");
for (int i = 0; i < array.length; i++) {
System.out.print(array[i] + ((i == array.length - 1) ?"" : ", "));
}
System.out.println("}");
}
}
The algorithm simply requires sorting the collection through a number of steps,
first sort the collection according to the first digit to the right and have all the elements that in buckest of 0 - 9 according to that last digit while maintaining the initial order of the collection, then starting from bucket 0 reassemle the collection again and proceed to sorting according to the next digit to the left and so on.
the program does work and sorts the collection fine.

I bet the output you get is not the same one as you expect since the following line results in:
array[i] = itInteger.next();
Type mismatch: cannot convert from Integer to int[]
As far as I understand you want to convert List<List<Integer>> structure to the array of the same type. You also need to map Integer to int using Stream::mapToInt:
int array[][] = new int[buckets.size()][];
IntStream.range(0, buckets.size())
.forEach(i -> array[i] = buckets.get(i)
.stream()
.mapToInt(j -> j.intValue())
.toArray());
System.out.println(Arrays.deepToString(array)); // Prints the very same output
Also, you don't need to use Iterator, however if you insist on it:
int outerIndex = 0;
while (outerIterator.hasNext()) {
List<Integer> list = outerIterator.next();
Iterator<Integer> innerIterator = list.iterator();
array[outerIndex] = new int[list.size()];
int innerIndex = 0;
while (innerIterator.hasNext()) {
array[outerIndex][innerIndex] = innerIterator.next().intValue();
innerIndex++;
}
outerIndex++;
}
Are there any dangers or side effects for using this simple form?
Yes, both of the solutions are since they don't amend the original resource of input nor affect another resource.

Your code will be clearer if you use enhanced for loops instead of iterators:
int i = 0;
for (List<Integer> intList : buckets) {
for (int value : intList) {
arr[i++] = value;
}
}

Related

Program throws a ArrayIndexOutOfBoundsException when using Bucket Sort on an array that's sorted backwards

I need to run an array that's sorted backwards (I.E. 100, 99, 98, 97 . . . . 3, 2, 1, 0, highest to lowest) through a bucket sort that will sort it lowest to highest. The code that generates the array looks like this:
int n = 100;//Decides how large the arrays fed to the sorts are, minimum value of 100
int k = n - 1;
int howMany = 10;//Decides how many times the sorts are timed whenever the program is run
int[] baseArray = new int[n];
//Loops entire thing as many times as howMany dictates, will refer to it as PRIME LOOP
for (int m = 0; m < howMany; m++) {
for (int i = 0; i < n; i++) //Generates array that's sorted backwards
{
baseArray[i] = k;
k--;
}
int[] bucketArray = new int[n];
for (int i = 0; i < n; i++) {
bucketArray[i] = baseArray[i];
}
bucketSort(bucketArray); //Sends the array to bucket sort (This is line 218)**************
}
Here's the actual bucket sort:
//Bucket Sort
public static void bucketSort(int[] input) {
// get hash codes
final int[] code = hash(input);
// create and initialize buckets to ArrayList: O(n)
List<Integer>[] buckets = new List[code[1]];
for (int i = 0; i < code[1]; i++) {
buckets[i] = new ArrayList();
}
// distribute data into buckets: O(n)
for (int i : input) {
buckets[hash(i, code)].add(i); //This is line 349*******************************************
}
// sort each bucket O(n)
for (List bucket : buckets) {
Collections.sort(bucket);
}
int ndx = 0;
// merge the buckets: O(n)
for (int b = 0; b < buckets.length; b++) {
for (int v : buckets[b]) {
input[ndx++] = v;
}
}
}
private static int[] hash(int[] input) {
int m = input[0];
for (int i = 1; i < input.length; i++) {
if (m < input[i]) {
m = input[i];
}
}
return new int[] { m, (int) Math.sqrt(input.length) };
}
private static int hash(int i, int[] code) {
return (int) ((double) i / code[0] * (code[1] - 1));
}
The first time the code goes through the for-loop (prime loop) bucket sort spits out the array with it properly sorted lowest to highest. However, without fail the second time it goes through the prime loop it gives me an ArrayIndexOutOfBoundsException, specifically,
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 18 out of bounds for length 10
at SeniorResearch.Final_Project_Driver.bucketSort(Final_Project_Driver.java:349)
at SeniorResearch.Final_Project_Driver.main(Final_Project_Driver.java:218)
(I marked out the mentioned lines above)
Can anyone help me figure out why this is happening? What's changing from PRIME LOOP 1 to PRIME LOOP 2 that's causing an ArrayIndexOutOfBoundsException in the bucket sort and how do I fix it?
In your bucketSort method at you think you are using final int[] code = hash(input); to calculate the number of buckets, but in reality, you are calculating the hash of your array.
So what you have to do is calculate the number of different hash codes for your array elements.
Use the method which calculates the hash of a single integer, then count how many different hashes you've got, then add each integer into the "hash-bucket", and so on...

Java- How to find the permutation of all values in a 1 dimensional array and store them in a 2 dimensional array

I want to create a method in which, when given a 1 dimensional array, it'll find all permutations of the values in that array and make it into a 2 dimensional array. I found some algorithms online which finds all the permutations but only prints the values out in the form of a 2d array(example), but I couldn't quite modify the code to store the output into a single 2d array. Any help would be appreciated, thank you.
Here's how I would do it - adapted from the link in your question:
import java.util.List;
import java.util.LinkedList;
import java.util.Iterator;
// Java program to calculate all permutations using
// Heap's algorithm
class HeapAlgo
{
List<int[]> heapPermutation(int a[]) {
LinkedList<int[]> list = new LinkedList<int[]>();
heapPermutation(a, a.length, a.length, list);
return list;
}
//Generating permutation using Heap Algorithm
void heapPermutation(int a[], int size, int n, List<int[]> list)
{
// if size becomes 1 then adds the obtained
// permutation to the list
if (size == 1)
list.add(a.clone());
for (int i=0; i<size; i++)
{
heapPermutation(a, size-1, n, list);
// if size is odd, swap first and last
// element
if (size % 2 == 1)
{
int temp = a[0];
a[0] = a[size-1];
a[size-1] = temp;
}
// If size is even, swap ith and last
// element
else
{
int temp = a[i];
a[i] = a[size-1];
a[size-1] = temp;
}
}
}
// Driver code
public static void main(String args[])
{
HeapAlgo obj = new HeapAlgo();
int a[] = {1,2,3};
List<int[]> list = obj.heapPermutation(a);
for(Iterator<int[]> i = list.iterator(); i.hasNext();) {
int[] array = i.next();
for(int j = 0; j < array.length; j++) {
System.out.print(array[j] + " ");
}
System.out.println();
}
}
}
// Based on code contributed by Amit Khandelwal.
Another approach would be to create an array of int[] arrays. The length would be the factorial of the length of a. You could create a stack class that tracks the lowest empty index to add the next permutation to.

Changing 2D ArrayList code to 2D array code

I found this code online and it works well to permute through the given array and return all possible combinations of the numbers given. Does anyone know how to change this code to incorporate a 2D array instead?
public static ArrayList<ArrayList<Integer>> permute(int[] numbers) {
ArrayList<ArrayList<Integer>> permutations = new ArrayList<ArrayList<Integer>>();
permutations.add(new ArrayList<Integer>());
for ( int i = 0; i < numbers.length; i++ ) {
ArrayList<ArrayList<Integer>> current = new ArrayList<ArrayList<Integer>>();
for ( ArrayList<Integer> p : permutations ) {
for ( int j = 0, n = p.size() + 1; j < n; j++ ) {
ArrayList<Integer> temp = new ArrayList<Integer>(p);
temp.add(j, numbers[i]);
current.add(temp);
}
}
permutations = new ArrayList<ArrayList<Integer>>(current);
}
return permutations;
}
This is what I have attempted:
public static int[][] permute(int[] numbers){
int[][] permutations = new int[24][4];
permutations[0] = new int[4];
for ( int i = 0; i < numbers.length; i++ ) {
int[][] current = new int[24][4];
for ( int[] permutation : permutations ) {
for ( int j = 0; j < permutation.length; j++ ) {
permutation[j] = numbers[i];
int[] temp = new int[4];
current[i] = temp;
}
}
permutations = current;
}
return permutations;
}
However this returns all zeroes. I chose 24 and 4 because that is the size of the 2D array that I need.
Thanks
It’s not really that easy. The original code exploits the more dynamic behaviour of ArrayList, so a bit of hand coding will be necessary. There are many correct thoughts in your code. I tried to write an explanation of the issues I saw, but it became too long, so I decided to modify your code instead.
The original temp.add(j, numbers[i]); is the hardest part to do with arrays since it invloves pushing the elements to the right of position j one position to the right. In my version I create a temp array just once in the middle loop and shuffle one element at a time in the innermost loop.
public static int[][] permute(int[] numbers) {
// Follow the original here and create an array of just 1 array of length 0
int[][] permutations = new int[1][0];
for (int i = 0; i < numbers.length; i++) {
// insert numbers[i] into each possible position in each array already in permutations.
// create array with enough room: when before we had permutations.length arrays, we will now need:
int[][] current = new int[(permutations[0].length + 1) * permutations.length][];
int count = 0; // number of new permutations in current
for (int[] permutation : permutations) {
// insert numbers[i] into each of the permutation.length + 1 possible positions of permutation.
// to avoid too much shuffling, create a temp array
// and use it for all new permutations made from permutation.
int[] temp = Arrays.copyOf(permutation, permutation.length + 1);
for (int j = permutation.length; j > 0; j--) {
temp[j] = numbers[i];
// remember to make a copy of the temp array
current[count] = temp.clone();
count++;
// move element to make room for numbers[i] at next position to the left
temp[j] = temp[j - 1];
}
temp[0] = numbers[i];
current[count] = temp.clone();
count++;
}
assert count == current.length : "" + count + " != " + current.length;
permutations = current;
}
return permutations;
}
My trick with the temp array means I don’t get the permutations in the same order as in the origianl code. If this is a requirement, you may copy permutation into temp starting at index 1 and shuffle the opposite way in the loop. System.arraycopy() may do the initial copying.
The problem here is that you really need to implement properly the array version of the ArrayList.add(int,value) command. Which is to say you do an System.arraycopy() and push all the values after j, down one and then insert the value at j. You currently set the value. But, that overwrites the value of permutation[j], which should actually have been moved to permutations[j+1] already.
So where you do:
permutation[j] = numbers[i];
It should be:
System.arraycopy(permutation,j, permutations, j+1, permutations.length -j);
permutation[j] = numbers[i];
As the ArrayList.add(int,value) does that. You basically wrongly implemented it as .set().
Though personally I would scrap the code and go with something to dynamically make those values on the fly. A few more values and you're talking something prohibitive with regard to memory. It isn't hard to find the nth index of a permutation. Even without allocating any memory at all. (though you need a copy of the array if you're going to fiddle with such things without incurring oddities).
public static int[] permute(int[] values, long index) {
int[] returnvalues = Arrays.copyOf(values,values.length);
if (permutation(returnvalues, index)) return returnvalues;
else return null;
}
public static boolean permutation(int[] values, long index) {
return permutation(values, values.length, index);
}
private static boolean permutation(int[] values, int n, long index) {
if ((index == 0) || (n == 0)) return (index == 0);
int v = n-(int)(index % n);
int temp = values[n];
values[n] = values[v];
values[v] = temp;
return permutation(values,n-1,index/n);
}

How to create int array containing (quasi) random values in a given range but with a fixed % of duplicates?

I am trying to create (in Java) an integer array containing a specified number of integers, k, (for example, 50, 500, 1000, etc.) that does not use library functions or Collections, but contains a random assortment of numbers in the range (i.e. from 1 to k), with a specified percentage of duplicates.
I have figured out how to implement the shuffle, but I am not sure how to best implement the dups threshold. What I have so far:
static void shuffle(int[] array) {
int n = array.length;
for (int i = 0; i < array.length; i++) {
// Get a random index of the array past i.
int random = i + (int) (Math.random() * (n - i));
// Swap the random element with the present element.
int randomElement = array[random];
array[random] = array[i];
array[i] = randomElement;
}
}
Then, using this method:
//Create an ascending ordered array of size k to be shuffled
int [] tempInit = new int [filesizes[i]];
for(int k = 0; k < filesizes[i]; k++)
{
tempInit[k] = k+1;
}
//Shuffle the ascending array
shuffle(tempInit);
for(int k = 0; k < tempInit.length; k++)
{
System.out.println(tempInit[k]);
}
One way I imagine it could work would be to use the percentage of duplicates required (let's say it's 20%) and then randomly select a fixed number of integers, and loop through the array and replace every element (if not equal to one of the fixed numbers) with one of these fixed numbers. I'm not sure what sort of logic would make sense to select these fixed numbers, or the amount of fixed numbers to use for replacement purposes.
Try this! For 80% for number 1 and 5% for each other up to 5:
Map<Double, Integer> map = new LinkedHashMap<>();
map.put(0.8, 1);
map.put(0.85, 2);
map.put(0.9, 3);
map.put(0.95, 4);
map.put(1, 5);
Random random = new Random();
double result = random.nextDouble();
int value = map.entrySet().stream().filter(entry -> entry.getKey() < result).reduce(0, Math::min);
edit: solved this as follows:
double percentDupes= 0.2;
//Create an ascending ordered array of size k to be shuffled
int [] tempSorted = new int [filesizes[i]];
for(int k = 0; k < filesizes[i]; k++)
{
tempSorted[k] = k+1;
}
//Shuffle the ascending array
shuffleArray(tempSorted);
//Figure out the proportion of the array to replace with duplicate values of elements already in the array
Double proportion = tempSorted.length*percentDupes;
int ratio = proportion.intValue();
//Instantiate a new array of size "ratio"
int [] tempShuffled = new int[ratio];
//Fill the new, smaller array with randomly selected elements from the original, sorted array
for(int b = 0; b< tempShuffled.length; b++)
{
int randNum = i + (int) (Math.random() * (tempSorted.length - i)); //Select a random element of the array to have as a duplicate
tempShuffled[b] = tempSorted[randNum]; //tempSorted was previously shuffled
}
//Shuffle this sub-array
shuffleArray(tempShuffled);
//Loop through (shuffled) original array and, if the values don't match, replace a non-dup with a dup value
for(int c= 0; c<tempShuffled.length; c++ )
{
if(tempSorted[c] != tempShuffled[c])
{
tempSorted[c] = tempShuffled[c];
}
}
//Final output to print to file
for(int k = 0; k < tempSorted.length; k++)
{
System.out.println(tempSorted[k]);
}

php's array_multisort function equivalent in java

I was looking for an equivalent of *php's array_multisort* in java.
//array 1
ar1 = array(10, 100, 100, 0);
//array 2
ar2 = array(1, 3, 2, 4);
//calling the function
//this will sort the array at first based one the first array and then based on the
//second array so these two array are related
array_multisort(ar1, ar2);
//resultant 1st array
array(4) {
[0]=> int(0)
[1]=> int(10)
[2]=> int(100)
[3]=> int(100)
}
//resultant 2nd array
//this array has been sorted based on the first array at first
array(4) {
[0]=> int(4) // this is associative element of 0 in the first array
[1]=> int(1) //this is associative element of 10 in the first array
[2]=> int(2) //this is associative element of 1st 100 from the last in the first array
//as there are two 100's , and last one's associative value in the second
//array is smaller it will come first
[3]=> int(3)
}
how can i achieve this result using something built-in , i know how to implement it using custom code.
N.B. *Please visit this link before answering the question as that explains how the function should work*
This is a bit more complicated and can't be done without the Java standard API. So I have recycled a quicksort implementation and made it work for multiple arrays. Basically it swaps the elements when they are swapped by the partitioning of quicksort.
Here you go:
/**
* Multi-sorts the given arrays with the quicksort algorithm. It assumes that
* all arrays have the same sizes and it sorts on the first dimension of these
* arrays. If the given arrays are null or empty, it will do nothing, if just
* a single array was passed it will sort it via {#link Arrays} sort;
*/
public static void multiQuickSort(int[]... arrays) {
multiQuickSort(0, arrays);
}
/**
* Multi-sorts the given arrays with the quicksort algorithm. It assumes that
* all arrays have the same sizes and it sorts on the given dimension index
* (starts with 0) of these arrays. If the given arrays are null or empty, it
* will do nothing, if just a single array was passed it will sort it via
* {#link Arrays} sort;
*/
public static void multiQuickSort(int sortDimension, int[]... arrays) {
// check if the lengths are equal, break if everything is empty
if (arrays == null || arrays.length == 0) {
return;
}
// if the array only has a single dimension, sort it and return
if (arrays.length == 1) {
Arrays.sort(arrays[0]);
return;
}
// also return if the sort dimension is not in our array range
if (sortDimension < 0 || sortDimension >= arrays.length) {
return;
}
// check sizes
int firstArrayLength = arrays[0].length;
for (int i = 1; i < arrays.length; i++) {
if (arrays[i] == null || firstArrayLength != arrays[i].length)
return;
}
multiQuickSort(arrays, 0, firstArrayLength, sortDimension);
}
/**
* Internal multi quicksort, doing the real algorithm.
*/
private static void multiQuickSort(int[][] a, int offset, int length,
int indexToSort) {
if (offset < length) {
int pivot = multiPartition(a, offset, length, indexToSort);
multiQuickSort(a, offset, pivot, indexToSort);
multiQuickSort(a, pivot + 1, length, indexToSort);
}
}
/**
* Partitions the given array in-place and uses the end element as pivot,
* everything less than the pivot will be placed left and everything greater
* will be placed right of the pivot. It returns the index of the pivot
* element after partitioning. This is a multi way partitioning algorithm, you
* have to provide a partition array index to know which is the array that
* needs to be partitioned. The swap operations are applied on the other
* elements as well.
*/
private static int multiPartition(int[][] array, int start, int end,
int partitionArrayIndex) {
final int ending = end - 1;
final int x = array[partitionArrayIndex][ending];
int i = start - 1;
for (int j = start; j < ending; j++) {
if (array[partitionArrayIndex][j] <= x) {
i++;
for (int arrayIndex = 0; arrayIndex < array.length; arrayIndex++) {
swap(array[arrayIndex], i, j);
}
}
}
i++;
for (int arrayIndex = 0; arrayIndex < array.length; arrayIndex++) {
swap(array[arrayIndex], i, ending);
}
return i;
}
/**
* Swaps the given indices x with y in the array.
*/
public static void swap(int[] array, int x, int y) {
int tmpIndex = array[x];
array[x] = array[y];
array[y] = tmpIndex;
}
Done a little testcase to test your input from the question:
#Test
public void testMultiQuickSort() {
int[] first = new int[] { 10, 100, 100, 0 };
int[] second = new int[] { 1, 3, 2, 4 };
int[] resFirst = new int[] { 0, 10, 100, 100 };
int[] resSecond = new int[] { 4, 1, 2, 3 };
ArrayUtils.multiQuickSort(first, second);
for (int i = 0; i < first.length; i++) {
assertEquals(resFirst[i], first[i]);
assertEquals(resSecond[i], second[i]);
}
}
Seems to work ;)
BTW if you need it for an arbitrary object type, just leave a comment.
A multi-dimensional array is just an array of arrays, so iterate over the individual arrays and sort them:
int[][] marr = // your multi-dimensional array here
for (int[] arr : marr) {
Arrays.sort(arr);
}
And if, for whatever possible reason, you only want to sort the first array in the second dimension, this will do:
Arrays.sort(marr[0]);
Argh, now I understand what you want. If your elements (at least those of the first array) are unique, you can do it via a SortedMap:
if(arr1.length!=arr2.length)throw new IllegalArgumentException();
SortedMap<Integer,Integer> map = new TreeMap<Integer, Integer>();
for (int i = 0; i < arr1.length; i++) {
map.put(arr1[i],arr2[i]);
}
int ct = 0;
for (Entry<Integer, Integer> entry : map.entrySet()) {
arr1[ct]=entry.getKey();arr2[ct]=entry.getValue();
ct++;
}
It's look like that there is not any built-in library function / class for this purpose in Java .
If you are also facing this problem like me , so far Thomas's answer about the custom code can help you.
implements Comparator or using algorithm bubble sort
Arrays.sort(stringArray); it will sort only one array
Maybe the following code will help you.
You should use Arrays.sort()
Example:
import java.util.Arrays;
String [] stringArray = {"ab", "aB", "c", "0", "2", "1Ad", "a10"};
//order Ascending
Arrays.sort(stringArray);
//Descending
Arrays.sort(stringArray, Collections.reverseOrder());

Categories

Resources