quick sort on multidimensional array - java

Edit: I want this method to sort in ascending order based on any column the user want (each data in the same respective row is 'attached' to each other). There are 4 column in the table. if the user want to sort in based on first column then he should do something like
mySortedTable[][] = ClassName.quickSort(myUnsortedTable,0);
As you can see I tried to code what my title said. For some reason our data table is organized in a 2d Array of Strings(which is NOT handy, had to convert back and forth to implement ArrayList). I used the first data as the pivot. Mind debugging it together with me? :)
public static String[][] quickSort(String[][] data,int column) {
//1st step, create ArrayLists needed and compare the data by the pivot to determine which ArrayList to be filled.
ArrayList<String[]> hiData = new ArrayList<String[]>();
ArrayList<String[]> loData = new ArrayList<String[]>();
ArrayList<String[]> pivots = new ArrayList<String[]>();
String[] pivot = {data[0][0],data[0][1],data[0][2],data[0][3]};
for(String[] row : data) {
if(row[column].compareTo(pivot[column])<0)
loData.add(row);
else if (row[column].compareTo(pivot[column])>0)
hiData.add(row);
else pivots.add(row);
}
//To decide whether is needed to create the array from the ArrayList for recursively sort the parted data.
if(loData.size()>0) {
String[][] loDataArr = new String[loData.size()][4];
for(int i=0;i<loData.size();i++)
loDataArr[i]=loData.get(i);
if(loData.size()>1)
loDataArr = quickSort(loDataArr,column);
}
if(hiData.size()>0) {
String[][] hiDataArr = new String[hiData.size()][4];
for(int i=0;i<hiData.size();i++)
hiDataArr[i]=hiData.get(i);
if(hiData.size()>1)
hiDataArr = quickSort(hiDataArr,column);
}
//Combine parted data into new array and return it to feed the recursive back up until the first recursive call.
String result[][] = new String[hiData.size()+loData.size()+pivots.size()][4];
int j=0;
for(String[] row : loData) {
result[j]=row;
j++;
}
for(String[] row : pivots) {
result[j]=row;
j++;
}
for(String[] row : hiData) {
result[j]=row;
j++;
}
return result;
}
It outputs all the arrays, but is not sorted and also not equals with the arrays it started with. Also side question, I want to ask if ArrayList<String[]> do NOT smells bad, or is it?

In Java, arrays are always one dimensional - although their element type may be an array itself. So a two dimensional array in Java is just an array of arrays.
This fact becomes very handy when you want to sort an array so that rows stick together. You treat each row as an object, and use a comparator to compare the object.
Here is a little demonstration:
public class SortDemonstration {
public static void main(String[] args) {
String[][] table = {
{"The", "Quick", "Brown"},
{"Fox", "Jumped", "Over"},
{"A", "Lazy", "Dog"}
};
Arrays.sort( table, new ColumnComparator(0));
System.out.println( Arrays.deepToString(table));
Arrays.sort( table, new ColumnComparator(1));
System.out.println( Arrays.deepToString(table));
Arrays.sort( table, new ColumnComparator(2));
System.out.println( Arrays.deepToString(table));
}
private static class ColumnComparator implements Comparator<String []>{
private final int index;
public ColumnComparator(int index) {
this.index = index;
}
#Override
public int compare(String[] o1, String[] o2) {
return o1[index].compareTo(o2[index]);
}
}
}
The ColumnComparator class is the key to the solution. It implements a comparator of two string arrays (two rows). It compares the rows based on the item at the index it was instantiated with.
Thus a new ColumnComparator(0) compares two rows based on the first column. A new ColumnComparator(1) compares two rows based on the second column, etc.
Now that you have this comparator class, you can sort an array of "rows" using it. The output from this program is:
[[A, Lazy, Dog], [Fox, Jumped, Over], [The, Quick, Brown]]
[[Fox, Jumped, Over], [A, Lazy, Dog], [The, Quick, Brown]]
[[The, Quick, Brown], [A, Lazy, Dog], [Fox, Jumped, Over]]

I found the problem in my code. I built the parted data using the unsorted ArrayList instead of the sorted 2 dimensional array.
//Second step...
String[][] loDataArr = new String[loData.size()][4];
String[][] hiDataArr = new String[hiData.size()][4];
if(loData.size()>0) {
for(int i=0;i<loData.size();i++)
loDataArr[i]=loData.get(i);
if(loData.size()>1)
loDataArr = quickSort(loDataArr,column);
}
if(hiData.size()>0) {
for(int i=0;i<hiData.size();i++)
hiDataArr[i]=hiData.get(i);
if(hiData.size()>1)
hiDataArr = quickSort(hiDataArr,column);
}
String result[][] = new String[hiData.size()+loData.size()+pivots.size()][4];
int j=0;
for(String[] row : loDataArr) {
result[j]=row;
j++;
}
for(String[] row : pivots) {
result[j]=row;
j++;
}
for(String[] row : hiDataArr) {
result[j]=row;
j++;
}
return result;
}

Related

How to get random string value without duplicate?

I want to fetch only a single company name and I want to fetch it only once. So if it already was fetched, it should not be fetched again.
Here is the code:
private static String[] billercompanies = {
"1st",
"TELUS Communications",
"Rogers Cablesystems",
"Shaw Cable",
"TELUS Mobility Inc",
"Nanaimo Regional District of",
"Credit Union MasterCard",
};
public static String GetBillerCompany(){
String randomBillerComp = "";
randomBillerComp = (billercompanies[new Random().nextInt(billercompanies.length)]);
return randomBillerComp;
}
Just shuffle the array you want using Collections
Collections.shuffle(List);
So simply create a list from your array
List<E> list = Arrays.asList(array);
Then shuffle it using the method above
Collections.shuffle(list);
Your list can be read from left to right as it was random.
So simply save the index
int currentIndex = 0;
public E getRandom(){
//If at the end, start over
if(++currentIndex == list.size()) {
currentIndex = 0;
shuffle(list);
}
return list.get(currentIndex);
}
Each time you want to forget the duplicate list you already used, simply shuffle the array again
Collections.shuffle(list);
Without index
You could simply remove the first value each time, once the list is empty, recreate it with the original array. As Ole V.V. pointer out, a List generated by Arrays.asList(E[]) doesn't support the remove methods so it is necessary to generate a new instance from it.
Here is a quick and simple class using this solution :
public class RandomList<E>{
E[] array;
List<E> list;
public RandomList(E[] array){
this.array = array;
buildList(array);
}
public E getRandom(){
if(list.isEmpty()) buildList(array);
return list.remove(0);
}
public void buildList(E[] array){
list = new ArrayList<E>(Arrays.asList(array));
Collections.shuffle(list);
}
}
And the test was done with this small code :
Integer[] array = {1,2,3,4,5};
RandomList<Integer> rl = new RandomList(array);
int i = 0;
while(i++ < 10)
System.out.println(rl.getRandom());
Make a copy in a List and remove the element when it was already fetched.
Arrays.asList(array) is not modifiable but you can wrap it in a full featured List.
List<String> billercompaniesList = new ArrayList<>(Arrays.asList(billercompanies));
String randomBillerComp = "";
Random random = new Random();
// first retrieval
int index = random.nextInt(billercompaniesList.size());
randomBillerComp = billercompaniesList.get(index);
billercompaniesList.remove(index);
// second retrieval
index = random.nextInt(billercompaniesList.size());
randomBillerComp = billercompaniesList.get(index);
billercompaniesList.remove(index);
// and so for

Print values of a 2D ArrayList Matrix

I have a 2D Arraylist matrix like
ArrayList[][] table = new ArrayList[10][10];
table[0][0] = new ArrayList();
table[0][1].add(10);
table[1][0].add(20);
table[1][1].add(30);
System.out.println("Value="+table[1][0].get()); //error line
The error occurs in the System.out.println line.
how do I print the values of the arraylist matrix??
can anyone suggest me a method??
You seem to think you have a 2-D matrix of numbers, stored as an ArrayList. That is not what you have at all. Instead, you have a 2-D matrix where each element is an ArrayList. That means you really have 3 dimensions represented in your code. I don't think that's what you want. There are several ways you could achieve two dimensions using the constructs you already have (i.e. without going to some external library).
A 2-D array of numbers
The array is an easy to understand construct, so let's start with that.
Number[][] table = new Number[10][10];
table[0][0] = 0;
table[0][1] = 10;
table[1][0] = 20;
table[1][1] = 30;
System.out.println("Value="+table[1][0].get());
This code declares a 2-D array of type Number, then initializes it with 10 rows and 10 columns. It then partially fills in numbers. As long as you access an element that has already been initialized, you'll be ok. Trying to access an element that hasn't yet been initialized (like table[3][4]) would be bad.
Another way to initialize an array
Number[][] table = { { 0, 10 }, { 20, 30 } };
System.out.println("Value=" + table[1][0]);
This is the same thing as before, but initialized all at once. This particular array only has 2 rows and 2 columns.
Nested ArrayLists
If you want to use an ArrayList instead of an array, that's fine. You just need to realize that the ArrayList actually will contain other ArrayLists, each of which will contain Numbers. Like so:
ArrayList<ArrayList<Number>> table = new ArrayList<>();
table.add(new ArrayList<>());
table.add(new ArrayList<>());
table.get(0).add(0);
table.get(0).add(10);
table.get(1).add(20);
table.get(1).add(30);
System.out.println("Value=" + table.get(1).get(0));
In this example, you first declare an ArrayList that contains ArrayLists that contain Numbers, and initialize the outer ArrayList. Then you create some inner ArrayLists, and finally give each of them some Numbers.
Summary
You can use arrays or ArrayLists as you prefer. You just have to initialize them correctly before accessing their elements. How to initialize depends on the data structure you choose.
All the codes
import java.util.ArrayList;
public class TwoD {
public void example1() {
Number[][] table = new Number[10][10];
table[0][0] = 0;
table[0][1] = 10;
table[1][0] = 20;
table[1][1] = 30;
System.out.println("\nExample 1");
System.out.println("Value=" + table[1][0]);
}
public void example2() {
Number[][] table = { { 0, 10 }, { 20, 30 } };
System.out.println("\nExample 2");
System.out.println("Value=" + table[1][0]);
}
public void example3() {
ArrayList<ArrayList<Number>> table = new ArrayList<>();
table.add(new ArrayList<>());
table.add(new ArrayList<>());
table.get(0).add(0);
table.get(0).add(10);
table.get(1).add(20);
table.get(1).add(30);
System.out.println("\nExample 3");
System.out.println("Value=" + table.get(1).get(0));
}
public static void main(String[] args) {
TwoD me = new TwoD();
me.example1();
me.example2();
me.example3();
}
}
THe actual exception is at the lines
table[0][0] = new ArrayList();
table[0][1].add(10);
You are adding element at 0,0 position and trying to add the arraylist element at 0,1.
Hence the nullpointer.
Try
public static void main(String[] args) {
ArrayList[][] table = new ArrayList[10][10];
table[0][0] = new ArrayList();
table[0][0].add(10);
table[0][0].add(20);
table[0][0].add(30);
System.out.println("Value="+table[0][0].get(1));
}
For using ArrayList, you must first declare the type of ArrayList in angular braces. Try using the code snippet as below:
ArrayList<ArrayList<Integer>> table = new ArrayList<ArrayList<Integer>>(); //2d ArrayList
ArrayList<Integer> x = new ArrayList<Integer>();
x.add(10);
x.add(20);
table.add(x);
table.add(x);
System.out.println("Value="+table); //Prints table[][]
System.out.println("Value="+table.get(0)); //Prints table[0]
System.out.println("Value="+table.get(0).get(1)); //Prints table [0][1]
To insert a new row, you must do
table.add(new ArrayList<Integer>());
and to append another element on a specific row you must do
table.get(row).add(someValue);
If you are looking for something more than toy project you should seriously consider using some external matrix library. Arrays will be painful in maintenance.
I could recommend EJML. With usage of this library your code will look like this:
BlockMatrix64F matrix = new BlockMatrix64F(10, 10);
matrix.set(0,1,10);
matrix.set(1,0,20);
matrix.set(1,1,30);
System.out.println("Value="+matrix.get(1,0));
Additionally it is quite likely that you will have to make some calculations inside your matrix. Library will have some support for basic ones, and will save you some time.

Moving indices in an array

I am trying to write a write a program that receives an String[] and prints out the array with the first string alphabetically first. I have to use three methods like these. Here is a sample input/output:
bob, joe, aaron, zack ----> aaron, bob, joe, zack
findFirstName() is correctly finding the first String alphabetically and returning its location.
MoveToRightOne is correctly shifting each String right one while overwriting the first string alphabetically and repeating the first one (ex: bob bob joe zack).
moveName() is not working correctly. It is supposed to replace the first instance of "bob" with "aaron" but is usually off by one or two places.
Does anyone see why this might be happening in moveOne()?
public static String [] moveName(String [] names) {
String names1 [] = names.clone();
int firstPosition = findFirstName(names1);
String[] NewNames = moveToRightOne(names1, firstPosition, firstPosition+1);
String firstAlph= names1 [firstPosition];
System.out.println(names1 [firstPosition]);
NewNames [0] = firstAlph;
return NewNames;
}
public static int findFirstName(String[ ] names1 ) {
// receives an array of Strings, and returns the location (i.e. index) of the first
// name (alphabetically)
String first=names1[0];
int firstPosition = 0;
for (int i=0; i<names1.length; i++) {
int result =names1[i].compareToIgnoreCase(first);
if (result < 0) {
first= names1[i];
firstPosition = i;
}
}
return firstPosition;
}
public static String[] moveToRightOne (String[] names, int startSpot, int endSpot) {
for (int i = (startSpot - 1); i >= 0; i--) {
names[i+1] = names[i];
}
return names;
}
moveToRightOne does not make a copy of the names array that you pass in. Instead, it modifies it directly. That means when you say
String[] NewNames = moveToRightOne(names1, firstPosition, firstPosition+1);
the strings will be shifted in names1, and after that, NewNames and names1 will just be references to the same array. I think your intent is to make NewNames be an array with the strings shifted, and leave names1 alone, but that isn't what's happening. That means that the following statement is going to return the wrong string:
String firstAlph= names1 [firstPosition];
(Or, since names1 is already a clone of names, maybe what you want is to use names instead of names1 when trying to access elements from the not-yet-shifted array.)
Your moveToRightOne function was broken, so you were not actually using all the parameters passed in. Also, you should grab the first name alphabetically before you actually overwrite it using that function.
public class Shift {
public static void moveName(String [] names) {
int firstPosition = findFirstName(names);
// Store the name at that position
String firstName = names[firstPosition];
moveToRightOne(names, 0, firstPosition);
names [0] = firstName;
}
public static int findFirstName(String[] names1) {
// receives an array of Strings, and returns the location (i.e. index)
// of the first name (alphabetically)
String first=names1[0];
int firstPosition = 0;
for (int i=0; i<names1.length; i++) {
int result =names1[i].compareToIgnoreCase(first);
if (result < 0) {
first= names1[i];
firstPosition = i;
}
}
return firstPosition;
}
public static void moveToRightOne (String[] names, int startSpot, int endSpot) {
for (int i = (endSpot - 1); i >= startSpot; i--) {
names[i+1] = names[i];
}
}
public static void main(String[] args) {
String[] original = new String[] { "bob", "joe", "aaron", "zac"};
for (String s: original) System.out.println(s);
System.out.println();
moveName(original);
for (String s: original) System.out.println(s);
}
}
Are you sure the moveToRightOne is correct? (if firstPosition is 0 you will get no changes as the for loop will not execute)
Just a quick Thought:
If you are looking do a sort manually (I assume this is for a class). I will also assume you are trying to implement insertion sort algorithm (otherwise Arrays.sort() is your friend). The way you are approaching it, it looks like you will be making multiple passes through the array to achieve a sort. if you want to do that switch to bubble sort instead.
The description of the insertion sort code will look something like this:
Start looping through your array, compare that the element at index is greater than element at index + 1. if not true move to the next element. if true compare the smaller element (call it A) to all previous elements until it is greater than the next previous element (lets call it B). Save a copy of A Shift all elements after B to the right (by 1) until you get to the A's old position . insert the copy of A into position just after B. Continue from the old A's index. Rinse/repeat until the end of the array
you may want to simplify your code in that case (and always check for edge conditions like 0 and Array.length)
HTH
Please use Arrays.sort() for sorting instead.This is not exact solution for the problem, but an alternate way for it.
import java.util.Arrays;
public class Test{
Public static void main(String args[]){
String str[]= {'Mike','Adam','Peter','Brian'};
System.out.println("str"+str[0]); // Mike
Arrays.sort(str);
System.out.println("str"+str[0]); //Adam
}
}

Re-order ArrayList Based on String Array's Order - Java

I have one arraylist and one String array. The String array contains IDs and the Array List contains the ids and information related to those Ids. This ArrayList is in an undesirable order. I have a String Array of the Ids in the order in which I want them to be in the ArrayList.
Semi-Pseudocode Example:
ArrayList<MyObject> myList = new ArrayList<MyObject>();
for (every username)
{
myList.add(new MyObject(id, username, content, country);
}
String[] ids = new String[myList.size()];
...Ids are added and sorted here...
I now have a list of Ids, in their correct order. Each Id in "myList" corresponds to an Id in the "ids" String Array. I want to sort "myList" based on the order of it's corresponding id in the "ids" String Array.
How can I re-sort my ArrayList in such a way?
Eg. if in Array list I have:
1. 123, Bob, test, USA
2. 1234, Vladimir, test, USA
3. 12345, Yoseph, test, USA
and in the String[] I have:
1. 1234
2. 123
3.12345
How can I reorder the ArrayList based off of the Ids in the String Array, thus producing:
1. 1234, Vladimir, test, USA
2. 123, Bob, test, USA
3. 12345, Yoseph, test, USA
One solution would be to iterate over the ids array, and search the object for the current id in the array. We know its final (desired) position: it is the index in the array (because we want the list sorted just like the array), so we can move this element to its final place in the list (we do this by swapping it with the element being at the position we're at currently in the array).
for (int i = ids.length - 1; i > 0; i--) { // Downward for efficiency
final String id = ids[i];
// Big optimization: we don't have to search the full list as the part
// before i is already sorted and object for id can only be on the remaining
for (int j = i; j >= 0; j--) // NOTE: loop starting at i
if (id.equals(myList.get(j).getId()) {
Collections.swap(myList, j, i);
break;
}
}
Note: the for loop omits the last element (i==0) because if all other elements are in place, the last is also in (its) place.
This is much faster than creating a comparator and using a sorting algorithm (which Collections.sort() does for example) because the order of the elements is already known (defined by the ids array) and sorting algorithms (no matter how smart the algorithms are) can only use the info [less | equals | greater] returned by comparators.
You could write your own Comparator based on the index in the array:
public class MyObjectComparator implements Comparator<MyObject> {
private List<String> ids;
public MyObjectComparator(String[] ids) {
this.ids = Arrays.asList(ids); // Copying the array would be safer
}
public int compare (MyObject obj1, MyObject obj2) {
return Integer.compare(ids.indexOf(obj1), ids.indexOf(obj2));
}
}
// Use it:
Collections.sort (myList, new MyObjectComparator(ids));
You simply need a comparator:
List<String> ids = Arrays.asList(array);
Collections.sort(list, new Comparator<MyObject>() {
#Override
public int compare(MyObject o1, MyObject o2) {
return Integer.compare(ids.indexOf(o1.getId()), ids.indexOf(o2.getId()));
}
});
Of course, if your list is large, this will be very inefficient. So you'd better build a Map<String, Integer> containing each ID as key and its position in the array as value, and use this map inside the comparator:
Map<String, Integer> idPositions = new HashMap<>();
for (int i = 0; i < array.length; i++) {
idPositions.put(array[i], i);
}
Collections.sort(list, new Comparator<MyObject>() {
#Override
public int compare(MyObject o1, MyObject o2) {
return idPositions.get(o1.getId()).compareTo(idPositions.get(o2.getId()));
}
});
crs_rawStepSeqNum: Your arrayList
crs_rawStepSeqNum: Same arrayList
for(int x =0;x<crs_rawStepSeqNum.size();x++)
if((x+1) < crs_rawStepSeqNum.size()) {
if (Integer.parseInt(crs_rawStepSeqNum.get(x)) > Integer.parseInt(crs_rawStepSeqNum.get(x + 1))) {
crs_rawStepSeqNum.set(x, crs_rawStepSeqNum.get(x + 1));
crs_rawStepSeqNum.set(x + 1, crs_StepSeqNum.get(x));
crs_StepSeqNum.clear();
crs_StepSeqNum.addAll(crs_rawStepSeqNum);
x=0;
}
}
}

Sort an 2D array by number of hits

I have two ArrayLists:
Array 01:
ArrayList<String> uniqueFiletypes --> which contains unique filetypes (e.g .zip etc..)
Array 02:
ArrayList<Integer> countFiletypes --> which counts how many of each filetype there is, for example 8 .zip's
And to skip right to the question:
I need to make some kind of "ranking", which means the highest count of filetypes gets the first place, etc...
Another problem: It must be an Object[][] (to support JTable), so it is possible to show the result easily.
Example of output: I have 8 .zips, 5 .java and 2 .docx
Object[][] = {{"1", ".zip", "8"},{"2", ".java", "5"}, {"3", ".docx", "2"}}
Where {PLACE, FILETYPE, COUNT}
I'm assuming the order of the items in both lists matches. I.e. the first item in the uniqueFiletypes list has the number of hits equal to the first number in the countFiletypes list.
I would do the following:
Loop through the lists, adding the entries to a Map.
Sort the list of countFiletypes in descending order.
Pull the file types from the map, adding them in the order they're now in in the ordered list.
Something like the following might do the trick:
public static void main(final String[] args) {
final ArrayList<String> uniqueFileTypes = new ArrayList<String>();
uniqueFileTypes.add(".java");
uniqueFileTypes.add(".zip");
uniqueFileTypes.add(".docx");
final ArrayList<Integer> countFileTypes = new ArrayList<Integer>();
countFileTypes.add(5);
countFileTypes.add(8);
countFileTypes.add(2);
final Map<Integer, String> countedFileTypes = new HashMap<Integer, String>();
for (int i = 0; i< uniqueFileTypes.size(); i++ ) {
countedFileTypes.put(countFileTypes.get(i), uniqueFileTypes.get(i) );
}
Collections.sort(countFileTypes);
Collections.reverse(countFileTypes);
final Object[][] data = new Object[countedFileTypes.size()][3];
for(int i = 0; i<countedFileTypes.size(); i++) {
final Integer count = countFileTypes.get(i);
data[i] = new Object[]{(i+1), countedFileTypes.get(count), count};
System.out.println("{" + (i+1) + "," + countedFileTypes.get(count) + "," + count + "}");
}
}
The main method and the system out aren't really needed, I just used them for testing my solution, which produced this output:
{1,.zip,8}
{2,.java,5}
{3,.docx,2}
Granted, this implies a link between the number of hits and the file type which may not be true. For example, if the docx and the java file format both have 9 hits, this solution wouldn't work.
Is it possible for you to merge the two ArrayLists to a single HashMap<String, Integer>?
This map can hold the entries consisting of the unique filetype (String) and its count (Integer). I suggest this because you have a direct link between a filetype and its count - this "link" can be expressed by a HashMap entry.
The conversion of the HashMap to an Object[][] can be done this way:
for (Map.Entry<?,?> entry : map.entrySet()) {
model.addRow(new Object[] { entry.getKey(), entry.getValue() });
}
With the HashMap sorting gets also easier as you do not need to handle two independent array lists.
First approach: As you will work with JTable, Use TableRowSorter as shown in the demo example of tutorial page
Second approach: Assuming you need it not only for JTable
Object[][] array = {{"1", ".zip", "8"},{"2", ".java", "5"}, {"3", ".docx", "2"}};
List<Object[]>data = Arrays.asList(array);
Comparator<Object[]>comparator = new Comparator<Object[]>() {
#Override
public int compare(Object[] o1, Object[] o2) {
return ((String)o1[2]).compareTo((String)o2[2]);
}
};
Collections.sort(data, Collections.reverseOrder(comparator));
array = (Object[][]) data.toArray();

Categories

Resources