Reputation: 1512
I have been working off of this SO question. However, my data is arranged slightly differently.
Without going into HOW the data is retrieved, suffice it to say the resulting array looks like this
String[2][]
[0] = String[4]
[1] = String[4]
The actual data, then is as follows
data = String[2][]
data[0]
data[0][0] = "Columbia"
data[0][1] = "Chile"
data[0][2] = "Asia"
data[0][3] = "US"
data[1]
data[1][0] = "B216"
data[1][1] = "B217"
data[1][2] = "A442"
data[1][3] = "N665"
I want to sort the entire array by data[0] in alphabetical order. Yet I realized that the solution provided in the referenced SO question is working off of a different array format.
My expected result would look like
data = String[2][]
data[0]
data[0][0] = "Asia"
data[0][1] = "Chile"
data[0][2] = "Columbia"
data[0][3] = "US"
data[1]
data[1][0] = "A442"
data[1][1] = "B217"
data[1][2] = "B216"
data[1][3] = "N665"
I'm not entirely certain how to obtain these results without iterating over each element and shifting them to a new array.
Any ideas?
Upvotes: 2
Views: 1424
Reputation: 1
package com.mycompany.stringsortingby2darray;
public class StringSortingby2dArray {
public static void main(String[] args) {
String data[][]= {{"MADHYAPRADESH",String.valueOf(1)},{"BHARAT",String.valueOf(2)},{"usa",String.valueOf(13)},{"Australia",String.valueOf(17)},{"UTTARPRADESH",String.valueOf(5)}};
for (int i = 0; i < data.length; i++) {
//for (int j = 0; j < data.length; j++) {
System.out.println(data[i][0]);
}
}
}
}
Upvotes: 0
Reputation: 114230
I can see three options for how to sort multiple arrays into the same order:
Create an array of indices, sort it using a Comparator
that refers to the array you want to sort by based on the index, then rearrange the arrays according to the sorted indices. Here is a sample:
Integer[] indices = new Integer[data[0].length];
for(int i = 0; i < data[0].length; i++)
indices[i] = i;
Arrays.sort(indices, new Comparator<Integer>() {
@Override
public int compare(Integer i1, Integer i2) {
return data[0][i1].compareTo(data[0][i2]);
}
});
The index array has to be of type Integer
rather than int
because Arrays
does not allow sorting primitives with a custom comparator. You can then rearrange both arrays by the index array doing something similar to the function below. I can't think of a way to do it in place without messing up the order and invalidating the index array.
public String[] rearrange(Integer[] indices, String[] input) {
String[] output = new String[];
for(int i = 0; i < indices.length; i++)
output[i] = input[indices[i]];
return output;
}
This function does no error checking to see if the inputs are the same length and it doesn't use streams, which I am sure it can be rewritten to do. It is just an example of the concept. To use it:
for(int i = 0; i < data.length; i++)
data[i] = rearrange(indices, data[i]);
This is probably the least memory-intensive option for rearranging the arrays. It is inspired by this answer to the question that I think is a duplicate of yours.
Create an object that holds all the elements at a given index and make it Comparable
. This is the solution to the accepted answer for the question referenced previously.
public class Container implements Comparable<Container>
{
public final String country;
public final String code;
public Container(Sting country, String code)
{
this.country = country;
this.code = code;
}
public int compareTo(Container other)
{
return this.country.compareTo(other.country);
}
}
You would have to transform your data into an array of these containers and then sort it:
objects = new Container[data[0].length];
for(int i = 0; i < objects.length; i++)
objects[i] = new Container(data[0][i], data[1][i]);
Arrays.sort(objects);
While this method does require copying the data over into a different format, it is actually more robust than working with an array of arrays because it groups the conceptually related items into a single item. This completely eliminates the need to check for things like array lengths being equal, as well as being generally much more object oriented. You could even rewrite your data input to just spit out an array or List
of Container
objects instead of a 2D array.
Create an explicit mapping between the countries and the codes, then dereference the values based on the sorted keys. This is sort of what #1 does, but it will allow you to at least sort one of the arrays in-place. If the mapping is an ordered mapping, you can just turn it into the sorted arrays directly.
a. Unsorted mapping:
HashMap<String, String> mapping = new HashMap<>();
for(int i = 0; i < data[0].length; i++)
mapping.put(data[0][i], data[1][i]);
Arrays.sort(data[0]);
String[] outputCodes = new String[data[1].length];
for(int i = 0; i < outputCodes.length; i++)
outputCodes[i] = mapping(data[0][i]);
data[1] = outputCodes;
b. Sorted mapping:
TreeMap<String, String> mapping = new TreeMap<>();
for(int i = 0; i < data[0].length; i++)
mapping.put(data[0][i], data[1][i]);
data[0] = new String[mapping.size()];
data[1] = new String[mapping.size()];
int index = 0;
for(Map.Entry<String, String> entry : mapping.entrySet()) {
data[0][index] = entry.getKey();
data[1][index] = entry.getValue();
index++;
}
These methods both have the disadvantage that they only really work well for two columns of data. If you have more than that, your values have to become custom objects or arrays of objects or something similar. Either way, this method is pretty clunky and I am only providing it to illustrate how you can jump through extra hoops if you really want to.
There are probably other ways, but as #3 demonstrates, I suspect that they will not be particularly efficient in terms of speed, memory or legibility/maintainability compared to the three shown here.
Also keep in mind that streams will let you do everything I have shown you here much easier.
Upvotes: 1
Reputation: 1512
Solution
Taking the advice of Socowi and Stephen P and Sorting multiple arrays simultaneously I came up with the following solution
As I am returning this data to a JSP to populate a drop down, I added a class for the model and iterated over the array adding a new instance of the model class to an Array List
for (int i = 0; i < data[0].length; i++) {
dataList.add(new LocationModel(data[0][i], data[1][i].trim()));
}
The model class implements Comparable and overrides the compareTo method
public class LocationModel implements Comparable<LocationModel> {
...
@Override
public int compareTo(LocationModel other) {
return this.locName.compareToIgnoreCase(other.getLocName());
}
}
Then I simply sort the Array List
Collections.sort(dataList);
This has solved my question.
Thanks everyone for your assistance
Upvotes: 0
Reputation: 2802
Complete code here
String[]
of data
.Add the data
to an ArrayList
List<String[]> list = new ArrayList<>();
// Sort the String array and insert it in List
for (String dataArr[] : data) {
String s[] = dataArr.clone(); // create new object of String array
Arrays.sort(s); // Sort newly created String array
list.add(s);
}
Use custom comparator to sort this list.
3.1 Keep in mind that you need to scan through the entire String[]
of the two arrays in comparision for finding the first difference.
// Sort the list using custom comparator
Collections.sort(list, new Comparator<String[]>() {
@Override
public int compare(String[] o1, String[] o2) {
// optional: condition to check for string length equality
if (o1.length == o2.length) {
for (int i = 0; i < o1.length; i++) {
if (o1[i].equals(o2[i])) { // ** IMP **
// allows scanning through entire string array.
continue;
}
// Find the first different strings in both arrays
return o1[i].compareTo(o2[i]);
}
} else if (o1.length < o2.length) {
// allow string arrays with lesser elements to appear first
return -1;
} else if (o1.length > o2.length) {
return 1;
}
// When o1.length == o2.length and all strings are equal
return 0; // no difference
}
});
Sample output for data (first line) and the sorted list
Upvotes: 1
Reputation: 1321
Try that. Works perfect for me.
Map<String, String> unsortMap = new HashMap<>();
unsortMap.put("Columbia", "B216");
unsortMap.put("Chile", "B217");
unsortMap.put("Asia", "A442");
unsortMap.put("US", "N665");
System.out.println("Original...");
System.out.println(unsortMap);
Map<String, String> result = new LinkedHashMap<>();
//sort by key, a,b,c..., and put it into the "result" map
unsortMap.entrySet().stream()
.sorted(Map.Entry.<String, String>comparingByKey())
.forEachOrdered(x -> result.put(x.getKey(), x.getValue()));
System.out.println("Sorted...");
System.out.println(result);
Upvotes: 0