Can anybody tell what is the best(easy) way to sort the following string 'index' array in java
String [] menuIndex= { "0",
"1",
"2",
"3",
"0.0",
"0.0.1",
"0.0.0",
"0.0.4",
"14" ,
"14.0",
"0.1" };
I need the sorted array in the following format
0,
0.0,
0.0.0,
0.0.1,
0.0.4,
0.1,
1,
2,
3,
14,
14.0
Plz help....
Since you have changed requirements, your own comparator is the right solution.
import java.util.Arrays;
import java.util.Comparator;
public class MyCmp implements Comparator<String> {
#Override
public int compare(String o1, String o2) {
String[] parts1 = o1.split("\\.");
String[] parts2 = o2.split("\\.");
int max = Math.max(parts1.length, parts2.length);
for (int i = 0; i < max; i++) {
if (i < parts1.length && i < parts2.length) {
Integer i1 = Integer.parseInt(parts1[i]);
Integer i2 = Integer.parseInt(parts2[i]);
if (i1 == i2)
continue;
return i1.compareTo(i2);
}
if (i < parts1.length) {
return 1;
}
if (i < parts2.length) {
return -1;
}
}
return 0;
}
public static void main(String[] args) {
String[] menuIndex = { "0",
"1",
"2",
"3",
"0.0",
"0.0.1",
"0.0.0",
"0.0.4",
"14",
"14.0",
"0.1" };
Arrays.sort(menuIndex, new MyCmp());
System.out.println(Arrays.toString(menuIndex));
}
}
Create your own comparator and sort the array using it.
Use Arrays.sort method for sorting..below is the code.
String [] menuIndex= { "0","1","2","3","0.0","0.0.1","0.0.0","0.0.4","4","4.0","0.1"};
Arrays.sort(menuIndex);
for(String str:menuIndex){
System.out.println(str);
}
Related
I have a JSONArray as below,
JSONArray dataArray = new JSONArray();
dataArray = [
{
"name": "name1",
"row": 1,
"value": 20
},
{
"name": "name2",
"row": 1,
"value": 10
},
{
"name": "name3",
"row": 2,
"value": 10
},
{
"name": "name4",
"row": 3,
"value": 30
},
{
"name": "name5",
"row": 3,
"value": 10
}
]
I need to compare the row attribute, if same, need to compare value attribute and sort the object in the array.
Tried with Java comparator, but couldn't make it work. Can somebody please help?
for(int i = 0; i < dataArray.size(); i++) {
elementList.add((JSONObject) dataArray.get(i));
}
Long row1 = null;
for (JSONObject obj : elementList) {
if(row1 == null) {
row1 = (Long) ((JSONObject) obj.get("row"));
}
else {
Long row2 = (Long) ((JSONObject) obj.get("row"));
if(row2 == row1) {
//call the comparator, but how to pass two objects?
}
row1 = row2;
}
}
It would be easy to extend this answer to match your scenario
But instead of
return valA.compareTo(valB);
you should do
int comp = valA.compareTo(valB);
if (comp == 0){
String valC = (String) a.get(KEY_NAME2);
String valD = (String) b.get(KEY_NAME2);
return valC.compareTo(valD);
} else {
return comp;
}
So it should be the following.
JSONArray sortedJsonArray = new JSONArray();
List<JSONObject> jsonValues = new ArrayList<JSONObject>();
for (int i = 0; i < dataArray.length(); i++) { // <---- dataArray is the input that you have
jsonValues.add(dataArray.getJSONObject(i));
}
Collections.sort( jsonValues, new Comparator<JSONObject>() {
//You can change "Name" with "ID" if you want to sort by ID
private static final String KEY_NAME1 = "row";
private static final String KEY_NAME2 = "value";
#Override
public int compare(JSONObject a, JSONObject b) {
String valA = new String();
String valB = new String();
try {
valA = (String) a.get(KEY_NAME1);
valB = (String) b.get(KEY_NAME1);
}
catch (JSONException e) {
//do something
}
int comp = valA.compareTo(valB);
if (comp == 0){
String valC = (String) a.get(KEY_NAME2);
String valD = (String) b.get(KEY_NAME2);
return valC.compareTo(valD);
} else {
return comp;
}
}
});
Edit: changed into KEY_NAME1 = "row"; to match the new question requirement
A simpler approach here:
You could convert your JSON string to List<YourObject> by using Jackson's ObjectMapper
List<YourObject> list = objectMapper.readValue(json, new TypeReference<List<YourObject>>(){});
Then use Collections.sort and Comparator to sort this list. You can also implement a custom Comparator to sort a list by multiple attributes depending on your situation.
list.sort(Comparator.comparing(YourObject::getRow)
.thenComparing(YourObject::getValue));
Let's assume you deserialize your json data into objects like
public class DataRow {
private String name;
private int row;
private int value;
// Getter, Setter, Constructor what ever needed
}
Then you can work with a list and stream like:
List<DataRow> datarows = //... read data from json
List<DataRow> sorted = datarows.stream()
.sorted(Comparator.comparing(DataRow::getRow).thenComparingInt(DataRow::getValue)).toList();
i'm trying to sort this ArrayList:
["1","1.1","1.2","1.3","2.1","2.3","4","4.1","6","7.1","8","8.1","10.1","2.4.7","2.2","2.4.8","3","2.4.2","2.4.9","2.4.5","5","5.1","7","2.4.4","2.4.6","2.4.1","2","2.4","3.1","6.1","9","9.1","10","11","11.1","12","12.1","13","2.4.3"]
i used Collections.sort(), but it's working only with decimals less than 10, because when an item has more than 10 decimals sort for the value in number but not in list order. For example a list from 1.1 to 1.14 the result is this:
1.1, 1.10, 1.11, 1.12, 1.13, 1.14, 1.2, 1.3, ... 1.8, 1.9
but should be like this:
1.1, 1.2, 1.3, ... 1.9, 1.10, 1.11, 1.12, 1.13, 1.14
And only with one decimal point.
Finally the result it should have is:
["1","1.1","1.2","1.3","2","2.1","2.2","2.3","2.4","2.4.1","2.4.2","2.4.3","2.4.4","2.4.5","2.4.6","2.4.7","2.4.8","2.4.9","3","3.1","4","4.1","5","5.1","6","6.1","7","7.1","8","8.1","9","9.1 ","10","10.1","11","11.1","12","12.1","13"]
I accept any suggestion.
Thanks
You can try with implementing your own custom comparator:
public class CustomComparator implements Comparator<String> {
#Override
public int compare(String version1, String version2) {
String[] parts1 = splitByParts(version1);
String[] parts2 = splitByParts(version2);
for (int i = 0; i < Math.min(parts1.length, parts2.length); i++) {
int partComparison = compareParts(parts1[i], parts2[i]);
if (partComparison != 0) {
return partComparison;
}
}
return Integer.compare(parts1.length, parts2.length);
}
protected String[] splitByParts(String version) {
return version.split("\\.");
}
private int compareParts(String firstPart, String secondPart) {
int firstPartValue = Integer.parseInt(firstPart);
int secondPartValue = Integer.parseInt(secondPart);
return Integer.compare(firstPartValue, secondPartValue);
}
}
And then just call:
String[] arr = {"1", "1.1", "1.2", "1.3", "2.1", "2.3", "4", "4.1", "6", "7.1", "8", "8.1", "10.1", "2.4.7", "2.2", "2.4.8", "3", "2.4.2", "2.4.9", "2.4.5", "5", "5.1", "7", "2.4.4", "2.4.6", "2.4.1", "2", "2.4", "3.1", "6.1", "9", "9.1", "10", "11", "11.1", "12", "12.1", "13", "2.4.3"};
Arrays.sort(arr, new CustomComparator());
for (String s : arr) {
System.out.println(s);
}
Please note that this is sorting in place.
I'm working on an application that read a file Excel with Apache POI. I put the cells value inside a matrix of String object.
[title 1][title 2][title 3]
[mark] [smith] [34]
[simon] [black] [24]
I've been ask to allow to order the matrix according to the selected column.
How can I order a matrix of String object?
Thank you
If you have only few columns you can create some comparators with a meaningful name and sort like below:
public static void main(String[] args) {
String[][] matrix = {{"mark","smith","34"},
{"simon","black","24"},
{"foo","bar","44"}
};
Comparator<String[]> firstNameComparator = new Comparator<String[]>() {
#Override
public int compare(String[] row1, String[] row2) {
return row1[0].compareTo(row2[0]);
}
};
Comparator<String[]> lastNameComparator = new Comparator<String[]>() {
#Override
public int compare(String[] row1, String[] row2) {
return row1[1].compareTo(row2[1]);
}
};
Comparator<String[]> ageComparator = new Comparator<String[]>() {
#Override
public int compare(String[] row1, String[] row2) {
return Integer.compare(Integer.parseInt(row1[2]), Integer.parseInt(row2[2]));
}
};
Arrays.sort(matrix, firstNameComparator);// pass the desired comparator
for(String[] row:matrix){
System.out.println(Arrays.toString(row));
}
}
or create a class that extends Comparator and pass the column index:
public class NewClass5 {
public static void main(String[] args) {
String[][] matrix = {{"mark","smith","34"},
{"simon","black","24"},
{"foo","bar","44"}
};
Arrays.sort(matrix, new CompareByColumn(1));// pass the desired index
for(String[] row:matrix){
System.out.println(Arrays.toString(row));
}
}
static class CompareByColumn implements Comparator {
int columnToSort;
CompareByColumn(int columnToSort) {
this.columnToSort = columnToSort;
}
public int compare(Object o1, Object o2) {
String[] row1 = (String[]) o1;
String[] row2 = (String[]) o2;
return row1[columnToSort].compareTo(row2[columnToSort]);
}
}
}
With java 8 and streams you can write it even more compactly:
String[][] sorted = Arrays.stream(matrix)
.sorted((s1,s2)->s1[1].compareTo(s2[1])) // pass the desired index
.toArray(String[][]::new);
for(String[] row: sorted){
System.out.println(Arrays.toString(row));
}
EDIT
Since you prefer the stream approach, I have only reworked this one. But you can use it for the other approaches as well. You can check before the comparison if the corresponding column contains numbers and make your comparison in a simple if-else either for numbers or strings.
int colIndex = 2;
String[][] sorted = Arrays.stream(matrix).sorted((s1,s2)-> {
if(s1[colIndex].matches("(\\d+(?:\\.\\d+)?)")){
return Double.compare(Double.parseDouble(s1[colIndex]), Double.parseDouble(s2[colIndex]));
}
else{
return s1[2].compareTo(s2[2]);
}})
.toArray(String[][]::new);
for(String[] row: sorted){
System.out.println(Arrays.toString(row));
}
Used this (\d+(?:\.\d+)?) regex to match both integer and floating point numbers.
First of all thank you for this question, it proved to be quite a mental challenge to visualize and implement this solution. I hope the following solution is what you wanted.
I've written a method that will sort the matrix for you. The method takes a String matrix as an argument and returns a new String matrix with each column sorted by alphabetic older. The sorting is done independent of other columns so each column is sorted without external context.
Unfortunately it doesn't exclude the titles from the sorting process so if you need that to happen please let me know and I will do my best to implement that.
public static boolean isNumeric(String str) {
return str.matches("^[0-9]+$");
}
public static String[][] sortMatrix(String[][] matrix)
{
int matrixLength = matrix[0].length;
String[][] sortedMatrix = new String[matrixLength][];
java.util.List<String[]> columns = new java.util.ArrayList<>();
for (int i1 = 0; i1 < matrixLength; i1++)
{
String[] column = new String[matrixLength];
for (int i2 = 0; i2 < matrixLength; i2++) {
column[i2] = matrix[i2][i1];
}
columns.add(column);
}
// First sort the column before proceeding
columns.forEach(column -> Arrays.sort(column, new Comparator<String>()
{
public int compare(String s1, String s2)
{
boolean i1 = isNumeric(s1);
boolean i2 = isNumeric(s2);
if (i1 && i2) {
return Integer.valueOf(s1).compareTo(Integer.valueOf(s2));
}
else if (!i1) {
return 1;
}
else return -1;
}
}));
for (int i1 = 0; i1 < columns.size(); i1++)
{
String[] row = new String[matrixLength];
for (int i2 = 0; i2 < matrixLength; i2++) {
row[i2] = columns.get(i2)[i1];
}
sortedMatrix[i1] = row;
}
return sortedMatrix;
}
public static void main(String[] args) throws IOException {
String[][] matrix = new String[3][] ;
matrix[0] = new String[] { "title 1", "title 2", "title 3" };
matrix[1] = new String[] { "simon", "1", "10" };
matrix[2] = new String[] { "mark", "35", "2" };
matrix = sortMatrix(matrix);
for (String[] row : matrix) {
System.out.println(Arrays.toString(row));
}
}
EDIT: Implemented a custom comparator that takes number into account.
I'm trying to make a basic "Deal or No Deal" game in Java. I'm running into issues with adding and removing to my multidimensional arraylist.
The issue occurs in line 7 of shuffleBoxes() and line 9 of playerBox().
package Deal;
import java.util.*;
import java.io.*;
import javax.swing.*;
public class sample {
public static ArrayList <ArrayList<Integer>> boxes = new ArrayList<ArrayList<Integer>>(22);
public static void main (String [] args) throws IOException {
playerBox();
dealerOffer();
}
public static void shuffleBoxes() {
int [] prizes = {1,2,3,4,5,6,10,50,100,250,500,750,1000,3000,10000,15000,20000,35000,50000,75000,100000,250000};
for (int i = 0; i < boxes.size(); i++) {
boxes.get(i).add(i+1);
}
for (int j = 0; j < boxes.size(); j++) {
boxes.get(j).get(1).add(prizes[j]);
}
Collections.shuffle(boxes);
}
public static int playerBox () {
String[] boxChoice = {"1", "2", "3", "4", "5", "6", "7", "8", "9" ,"10", "11", "12", "13",
"14", "15", "16", "17", "18", "19", "20", "21", "22"};
String input = (String)JOptionPane.showInputDialog(null, "Choose a box...", "Choose carefully",
JOptionPane.QUESTION_MESSAGE, null, boxChoice, boxChoice[0]);
int chosenBox = Integer.parseInt(input);
for (int i = 0; i < boxes.size(); i++) {
if (chosenBox == boxes.get(i).get(0))
boxes.get(i).get(0).remove(chosenBox);
}
return chosenBox;
}
public static void dealerOffer() {
int average;
int sum = 0;
for (int i = 0; i < boxes.size(); i++) {
sum = sum + (boxes.get(i).get(1));
}
average = sum / boxes.size();
}
}
You create
ArrayList <ArrayList<Integer>> boxes = new ArrayList<ArrayList<Integer>>(22);
but this does not put anything into the ArrayList. I don't see any references to boxes.add(...) in your code, so any attempt to use boxes.get() will throw an exception.
It is not at all clear why you think you need a List<List<Integer>>. A multidimensional list is generally code smell. In 99% of cases a different data structure using custom objects will be more appropriate.
The following code separates the duplicate names into 1 column and sum of numbers associated with the names into the second column.
Like :
Nokia 21
Blackberry 3
Nimbus 30
from the array given in the program.
I want to know the final length of the array that contain these entries. In this case 3. How do i calculate that ?
package keylogger;
import java.util.ArrayList;
import java.util.List;
public class ArrayTester {
private static int finalLength = 0;
private static String Name[][];
private static String data[][] = {
{"Nokia" , "7"},
{"Blackberry" ,"1"},
{"Nimbus","10"},
{"Nokia" , "7"},
{"Blackberry" , "1"},
{"Nimbus","10"},
{"Nokia" , "7"},
{"Blackberry" , "1"},
{"Nimbus","10"}
};
public void calculator() {
Name = new String[data.length][2];
List<String> marked = new ArrayList<String>();
try {
for(int i=0;i<data.length;i++) {
Name[i][0] = data[i][0];
Name[i][1] = data[i][1];
String name = data[i][0];
if(marked.contains(name)) {
continue;
}
marked.add(name);
int k = i + 1;
int v = k;
for (int j = 0; j < data.length - v; j++) {
String s = data[k][0];
if(Name[i][0].equalsIgnoreCase(s)) {
Name[i][0] = s;
Integer z = Integer.parseInt(Name[i][1]) + Integer.parseInt(data[k][1]);
Name[i][1] = z.toString();
}
k++;
}
}
}catch(Exception exc) {
exc.printStackTrace();
}
}
public static void main(String args[]) {
ArrayTester o = new ArrayTester();
o.calculator();
for(String s[] : Name) {
for(String x : s) {
System.out.println(x);
}
}
}
}
As usual, the "problem" is poor coding. Your entire program, properly written, can be reduced to just 3 lines of code (5 if you include defining the array and printing the output):
public static void main(String[] args) {
String data[][] = {{"Nokia", "7"}, {"Blackberry", "1"}, {"Nimbus", "10"},
{"Nokia", "7"}, {"Blackberry", "1"}, {"Nimbus", "10"}, {"Nokia", "7"},
{"Blackberry", "1"}, {"Nimbus", "10"}, {"Zebra", "78"}};
HashMap<String, Integer> totals = new HashMap<String, Integer>();
for (String[] datum : data)
totals.put(datum[0], new Integer(datum[1]) + (totals.containsKey(datum[0]) ? totals.get(datum[0]) : 0));
System.out.println("There are " + totals.size() + " brands: " + totals);
}
Output:
There are 4 brands: {Nimbus=30, Zebra=78, Nokia=21, Blackberry=3}
You can't know it a priori, the size will be known just when you'll have finished splitting the strings and doing your math.
In your example in the end marked.size() will have the size you are looking for but I'd suggest you to directly use a HashMap so that you won't care about searching for existing elements in linear time and then convert it to an array.
Something like:
String[][] names = new String[map.size()];
Set<String> keys = map.keys();
int c = 0;
for (String k : keys)
{
names[c] = new String[2];
names[c][0] = k;
names[c++][1] = map.get(k).toString();
}
As far as I understand it, you want to know the number of distinct names in your array without calling calculator(), right? I don't really know if that makes sense as you still have to go through every entry and compare it with a set. But you could do it with a Set:
private int getNumberOfEntries(String[][] data) {
Set<String> names = new HashSet<String>();
for (int i=0; i<data.length; i++) {
names.add(data[i][1]);
}
return names.size();
}
Now you can just call int n = getNumberOfEntries(data);...
EDIT: Of course it makes more sense to do the sums in the same step, see Bohemians solution for that.